CONTEXT

Bellabit is a high-tech company that manufactures health-focused smart products since 2013. Their products:

Bellabeat wants to get insights about the smart devices usage in order to obtain trends that help their marketing strategy.

ASK

Business task

Analyze smart device usage to gain insights into how people are already using their smart devices and provide high-level recommendations to improve marketing strategies for Bellabeat.

Business use case

  • Determine trends for smart device usage
  • How could these trends apply to Bellabeat ‘Time’ customers?
  • How could these trends help to improve Bellabeat’s marketing strategy?

PREPARE

For the analysis, I will use a custom survey (First-party data) in order to get updated data related to smartwatch usages, and use R with RStudio to perform the analysis task.

Building the survey

Platform

Build in Google Forms and available in 2 languages: English and Spanish. ### Distribution Distributed trough a link using LinkedIn post, Instagram stories and Whatsapp groups. No restrictions to share the link. ### Time frame Available for 7 days, starting on 01/26/2024 ### Configuration Anonymous survey ### Questions #### Demographic questions * Gender * Age * Geographic location

Smartwatch usage questions

  • Main usage: multiple choice, with the option to add a custom answer
  • Usage periodicity: scale from 0 to 7 representing usage in days
  • Brand: multiple choice, listing main brand collected from sites like Amazon, Tiendamia, Mercado Libre. Option for add custom answer.
  • Features used: checkboxs, listing main features offered by smartwatches on the market. Option for add custom answer.
  • Tracked functionalities: checkboxs, listing main tracker options offers the smartwatches on the market. Option for add custom answer.
  • Activities tracked: checkboxs, listing main sport activities tracked for the smartwatches on the market. Option for add custom answer.

Evaluating data

Installing packages

Error in install.packages : Updating loaded packages

Importing data

We need to import both survey files, the English and the Spanish version

swu_file_en <- read_csv("Smartwatch usage - english.csv")
swu_file_es <- read_csv("Smartwatch usage - Spanish.csv")

Get preview of imported data

We need to check if there is any error importing the files

head(swu_file_en)
head(swu_file_es)

Changing column names for both files

Every file has different column names because they were shared in different languages, though they show the same information

swu_es <- rename(swu_file_es, 
       'gender_dirty' = '¿Con qué genero te identificas?',
       'age_dirty' = '¿Qué edad tenés?',
       'location_dirty' = '¿Dónde vivís?',
       'usage_dirty' = '¿Cuál es el principal uso que le das a tu reloj inteligente?',
       'periodicity' = '¿Cuántos días utilizas alguna funcionalidad de tu reloj inteligente?',
       'brand_dirty' = '¿Cuál es la marca de tu reloj inteligente?',
       'features_dirty' = '¿Cuáles son las funciones que utilizas en tu reloj inteligente?',
       'functionalities_dirty' = '¿Qué funciones utilizas para realizar un seguimiento con tu reloj inteligente?',
       'activities_dirty' = '¿Qué actividades deportivas seguís con tu reloj inteligente?'
       )

swu_en <- rename(swu_file_en, 
       'gender_dirty' = 'What gender do you identify with?',
       'age_dirty' = 'How old are you?',
       'location_dirty' = 'Where do you live?',
       'usage_dirty' = 'Which is the main use you give to your smartwatch?',
       'periodicity' = 'How many days do you use any functionality of your smartwatch?',
       'brand_dirty' = 'Which is the brand of your smartwatch?',
       'features_dirty' = 'What are the features you use on your smartwatch?',
       'functionalities_dirty' = 'What features do you use to track with your smartwatch?',
       'activities_dirty' = 'What sport activities do you track with your smartwatch?'
       )

Binding files

We need to get one file to process the information

swu_dirty <- union(swu_es, swu_en)

Checking resulting dataframe

The resulting dataframe should have the sum of rows of both files

skim_without_charts(swu_dirty)
── Data Summary ────────────────────────
                           Values   
Name                       swu_dirty
Number of rows             621      
Number of columns          10       
_______________________             
Column type frequency:              
  character                9        
  numeric                  1        
________________________            
Group variables            None     

PROCESS

Preparing environment for cleaning data

General cleaning

We perform a general cleaning on the data: * clear names (to snake_case) * remove empty values

swu <- swu_dirty %>% clean_names() %>% remove_empty(c("rows", "cols"))

Translating fields

As we share the survey in 2 languages (English and Spanish), many of the answers need to be unified to count as one type of answer

Cleaning columns

Gender

unique(swu['gender_dirty'])
swu <- mutate(swu, gender = case_when(
  gender_dirty == 'Masculino' ~ 'Male',
  gender_dirty == 'Femenino' ~ 'Female',
  gender_dirty == 'Prefiero no decir' ~ 'Prefer not to say',
  TRUE ~ gender_dirty
))
unique(swu['gender'])

Age

unique(swu['age_dirty'])
swu <- mutate(swu, age = case_when(
  age_dirty == 'Más de 66' ~ 'More than 66',
  TRUE ~ age_dirty
))
unique(swu['age'])

User location

unique(swu['location_dirty'])
swu <- mutate(swu, location = case_when(
  location_dirty == 'Norteamérica' ~ 'North America',
  location_dirty == 'América Central y Sudamérica' ~ 'South America',
  location_dirty == 'Central and South America' ~ 'South America',
  location_dirty == 'Europa' ~ 'Europe',
  location_dirty == 'África' ~ 'Africa',
  location_dirty == 'Oceanía' ~ 'Australia',
  TRUE ~ location_dirty
))
unique(swu['location'])

Main usage

unique(swu['usage_dirty'])
swu <- mutate(swu, usage = case_when(
  
  grepl('(?i)entrenamiento|(?i)training', usage_dirty) ~ 'Training tracker',
  grepl('(?i)celular|(?i)cell|(?i)notification', usage_dirty) ~ 'Shortcut to cell',
  grepl('(?i)salud|(?i)health', usage_dirty) ~ 'Health tracker',
  
  # 'Other' options listed below
  grepl('(?i)opciones|(?i)options', usage_dirty) ~ 'All options',
  grepl('(?i)hora|(?i)reloj|(?i)time|(?i)watch', usage_dirty) ~ 'Watch usage',
  grepl('(?i)pago|(?i)pay|(?i)payment', usage_dirty) ~ 'Payments',
  
  TRUE ~ usage_dirty
))
unique(swu['usage'])

Brand

unique(swu['brand_dirty'])
swu <- mutate(swu, brand = case_when(
  
  grepl('I have Samsung and Colmi. Now I use Colmi', brand_dirty) ~ 'Colmi',
  grepl('(?i)Suunto', brand_dirty) ~ 'Suunto',
  grepl('Sinrelojinteligent|(?i)xxx', brand_dirty) ~ NA,
  
  TRUE ~ brand_dirty
))
unique(swu['brand'])

Group by demographic fields

We need to create new data frames for every multiple-value columns along with demographic fields for individual analysis

Features

‘Features’ is a question for knowing which are the common uses that an user gives to their smartwatch as a device.
The users should mark as many features as they used on their smartwatches. So, we need to split all this checked options into different rows to process them that way.

  features_dirty <- select(swu, timestamp, gender, age, location, periodicity, brand, features_dirty)
  features_rows <- separate_longer_delim(features_dirty, features_dirty, ', ')
unique(features_rows['features_dirty'])

We will create two different columns for features, the first is to translate the values and the second one to group them into a bigger category

features_rows <- mutate(features_rows, features = case_when(
  grepl('(?i)deporte|(?i)sport|(?i)pasos', features_dirty) ~ 'Sports monitor',
  grepl('(?i)alarma|(?i)alarm', features_dirty) ~ 'Alarm',
  grepl('(?i)sedentary|(?i)sedentarismo', features_dirty) ~ 'Sedentary reminder',
  grepl('(?i)agua|(?i)water', features_dirty) ~ 'Water drink reminder',
  grepl('(?i)notificaciones|(?i)notifications', features_dirty) ~ 'Cell notifications',
  grepl('(?i)slack|(?i)text', features_dirty) ~ 'Text messages',
  grepl('(?i)calendar', features_dirty) ~ 'Calendar',
  grepl('(?i)música', features_dirty) ~ 'Music',
  grepl('(?i)cámara|(?i)camara', features_dirty) ~ 'Camara',
  grepl('(?i)teléfono|(?i)telefónicas', features_dirty) ~ 'Phone calls',
  grepl('(?i)voz', features_dirty) ~ 'Voice control',
  grepl('(?i)hora|(?i)time|(?i)watch', features_dirty) ~ 'Watch',
  grepl('(?i)pago', features_dirty) ~ 'Contactless payments',
  grepl('(?i)calorías|(?i)salud|(?i)estres|(?i)sueño|(?i)presion|(?i)cardiaca', features_dirty) ~ 'Health monitor',
  grepl('(?i)clima|(?i)atmosfericos|(?i)weather', features_dirty) ~ 'Weather monitor',
  
  TRUE ~ features_dirty
))
unique(features_rows['features'])
features_grouped_rows <- mutate(features_rows, features_grouped = case_when(
  grepl('(?i)sports|(?i)sport', features) ~ 'Sports monitor',
  grepl('(?i)alarm|(?i)sedentary|(?i)water', features) ~ 'Activity reminder',
  grepl('(?i)notifications|(?i)text|(?i)email|(?i)calendar', features) ~ 'Cell notifications',
  grepl('(?i)music|(?i)camara|(?i)phone|(?i)voice', features) ~ 'Cell control',
  grepl('(?i)time|(?i)watch', features) ~ 'Watch',
  grepl('(?i)payment|(?i)SOS|(?i)GPS', features) ~ 'Other features',
  grepl('(?i)calories|(?i)stress|(?i)sleep|(?i)presion|(?i)cardiac', features) ~ 'Health monitor',
  grepl('(?i)weather', features) ~ 'Weather monitor',
  
  TRUE ~ features
))
unique(features_grouped_rows['features_grouped'])

Tracked functionalities

‘tracked_functionalities’ is a question to determine which are the features tracked by the users through their smartwatches. The users should mark as many features as they track on their smartwatches. So, we need to split all this checked options into different rows to process them that way.

  functionalities_dirty <- select(swu, timestamp, gender, age, location, periodicity, brand, functionalities_dirty)
  functionalities_rows <- separate_longer_delim(functionalities_dirty, functionalities_dirty, ', ')
unique(functionalities_rows['functionalities_dirty'])
functionalities_grouped_rows <- mutate(functionalities_rows, functionalities = case_when(
  grepl('(?i)deporte|(?i)sport|(?i)pasos', functionalities_dirty) ~ 'Sports',
  grepl('(?i)presión arterial|(?i)blood', functionalities_dirty) ~ 'Blood pressure',
  grepl('(?i)calorías|(?i)calorias|(?i)calories', functionalities_dirty) ~ 'Calories',
  grepl('(?i)distancia|(?i)distance', functionalities_dirty) ~ 'Distance',
  grepl('(?i)cardíaco|(?i)heart', functionalities_dirty) ~ 'Heart rate',
  grepl('(?i)sueño|(?i)sleep', functionalities_dirty) ~ 'Sleep',
  grepl('(?i)agua|(?i)water', functionalities_dirty) ~ 'Water',
  grepl('(?i)peso|(?i)weight', functionalities_dirty) ~ 'Weight',
  grepl('(?i)temperatura|(?i)temperature', functionalities_dirty) ~ 'Temperature',
  grepl('(?i)menstrual', functionalities_dirty) ~ 'Menstrual health',
  grepl('(?i)altitud|(?i)altitude|elevation', functionalities_dirty) ~ 'Altitude',
  grepl('(?i)oxigeno|(?i)oxígeno', functionalities_dirty) ~ 'Oxygen',
  grepl('(?i)estrés|(?i)stress', functionalities_dirty) ~ 'Stress',
  grepl('(?i)noise|(?i)ruido', functionalities_dirty) ~ 'Noise',
  grepl('(?i)hora', functionalities_dirty) ~ NA,
  
  TRUE ~ functionalities_dirty
))
unique(functionalities_grouped_rows['functionalities'])
functionalities_grouped_rows <- mutate(functionalities_grouped_rows, functionalities_grouped = case_when(
  grepl('(?i)sport|(?i)distance|(?i)altitude', functionalities) ~ 'Sports',
  grepl('(?i)blood|(?i)heart|(?i)sleep|(?i)temperature|(?i)oxygen|(?i)noise', functionalities) ~ 'Realtime health tracker',
  grepl('(?i)calories|(?i)water|(?i)weight|(?i)menstrual', functionalities) ~ 'Manual health tracker',
  grepl('(?i)stress|(?i)Mindfulness', functionalities) ~ 'Wellbeing',
  
  TRUE ~ functionalities
))
unique(functionalities_grouped_rows['functionalities_grouped'])

Activities

‘activities’ is a question to determine which are the sport activities most tracked for the smartwatch users.They should mark as many activities as they track on their smartwatches. So, we need to split all this checked options into different rows to process them that way.

  activities_dirty <- select(swu, timestamp, gender, age, location, periodicity, brand, activities_dirty)
  activities_rows <- separate_longer_delim(activities_dirty, activities_dirty, ', ')
unique(activities_rows['activities_dirty'])
activities_grouped_rows <- mutate(activities_rows, activities = case_when(
  grepl('(?i)caminata|(?i)pasos|(?i)walking|(?i)patinar|(?i)skating|(?i)bailar|(?i)dancing', activities_dirty) ~ 'Urban sports',
  grepl('(?i)correr|(?i)running|(?i)ciclismo|(?i)cycling|(?i)tenis|(?i)tennis|(?i)futbol|(?i)football|(?i)soccer|(?i)enduro', activities_dirty) ~ 'Professional sports',
  grepl('(?i)hiking|(?i)trakking|(?i)senderismo|(?i)splitboard|(?i)esqui|(?i)esquí|(?i)ski|(?i)escalada|(?i)climbing', activities_dirty) ~ 'Mountain sports',
  grepl('(?i)natación|(?i)natacion|(?i)swimming|(?i)buceo|(?i)diving', activities_dirty) ~ 'Water sports',
  grepl('(?i)gimnasio|(?i)gym|(?i)entrenamiento', activities_dirty) ~ 'General gym training',
  grepl('(?i)fuerza|(?i)crossfit|(?i)funcional|(?i)cross|(?i)strong|(?i)fitness|(?i)weight|(?i)strength|(?i)workouts', activities_dirty) ~ 'Strength and endurance sports',
  grepl('(?i)pilates|(?i)yoga|(?i)stretching|(?i)meditation', activities_dirty) ~ 'Relaxing sports',

  grepl('(?i)ninguna|(?i)hora', activities_dirty) ~ NA,
  
  TRUE ~ activities_dirty
))
unique(activities_grouped_rows['activities'])

ANALIZE

We need to identify trends and relationships within data so we can accurately answer the question made

install.packages('ggplot2')
Error in install.packages : Updating loaded packages
install.packages('lessR')
Installing package into ‘/Users/rho/Library/R/x86_64/4.3/library’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.3/lessR_4.3.0.tgz'
Content type 'application/x-gzip' length 6486185 bytes (6.2 MB)
==================================================
downloaded 6.2 MB

The downloaded binary packages are in
    /var/folders/rh/mhw1mj253_98zrx__sdr4rh80000gn/T//RtmpB56U0J/downloaded_packages
install.packages("ggplot2")
Installing package into ‘/Users/rho/Library/R/x86_64/4.3/library’
(as ‘lib’ is unspecified)
trying URL 'https://cran.rstudio.com/bin/macosx/big-sur-x86_64/contrib/4.3/ggplot2_3.4.4.tgz'
Content type 'application/x-gzip' length 4306767 bytes (4.1 MB)
==================================================
downloaded 4.1 MB

The downloaded binary packages are in
    /var/folders/rh/mhw1mj253_98zrx__sdr4rh80000gn/T//RtmpB56U0J/downloaded_packages
install.packages('scales')
Error in install.packages : Updating loaded packages
library(ggplot2)
library(lessR)

lessR 4.3.0                         feedback: gerbing@pdx.edu 
--------------------------------------------------------------
> d <- Read("")   Read text, Excel, SPSS, SAS, or R data file
  d is default data frame, data= in analysis routines optional

Learn about reading, writing, and manipulating data, graphics,
testing means and proportions, regression, factor analysis,
customization, and descriptive statistics from pivot tables
  Enter:  browseVignettes("lessR")

View changes in this and recent versions of lessR
  Enter: news(package="lessR")

Interactive data analysis
  Enter: interact()


Attaching package: ‘lessR’

The following objects are masked from ‘package:dplyr’:

    recode, rename
library(scales)

Attaching package: ‘scales’

The following object is masked from ‘package:lessR’:

    rescale

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor

Demographic

We want to identify demographic trends on the sample * Gender * Age * Geographic location

Gender

We identified two main genders and a third for those who rater not say.

gender_table <- table(swu['gender'])

PieChart(gender_table, hole = 0, values = "%", main = "Gender distribution", fill = "reds")
>>> Note: gender_table is not in a data frame (table)
>>> Note: gender_table is not in a data frame (table)
>>> suggestions
PieChart(gender_table, hole=0)  # traditional pie chart
PieChart(gender_table, values="%")  # display %'s on the chart
PieChart(gender_table)  # bar chart
Plot(gender_table)  # bubble plot
Plot(gender_table, values="count")  # lollipop plot 

--- gender_table --- 

               Female   Male  Prefer not to say     Total 
Frequencies:      238    370                 13       621 
Proportions:    0.383  0.596              0.021     1.000 

Chi-squared test of null hypothesis of equal probabilities 
  Chisq = 314.812, df = 2, p-value = 0.000 

Age

We created age groups, with a range of 10 years each.

age_table <- table(swu['age'])

PieChart(age_table, hole = 0, values = "%", main = "Age distribution", fill = "reds")
>>> Note: age_table is not in a data frame (table)
>>> Note: age_table is not in a data frame (table)
>>> suggestions
PieChart(age_table, hole=0)  # traditional pie chart
PieChart(age_table, values="%")  # display %'s on the chart
PieChart(age_table)  # bar chart
Plot(age_table)  # bubble plot
Plot(age_table, values="count")  # lollipop plot 

--- age_table --- 

               15 - 25  26 - 35  36 - 45  46 - 55  56 - 65  More than 66     Total 
Frequencies:       101      201      194       83       35             7       621 
Proportions:     0.163    0.324    0.312    0.134    0.056         0.011     1.000 

Chi-squared test of null hypothesis of equal probabilities 
  Chisq = 310.411, df = 5, p-value = 0.000 

Geographic location

We want to know which is the continent distribution of smartwatches users

# Tell sf to treat world map data as a 'flat' surface instead of a sphere
sf_use_s2(FALSE)
Spherical geometry (s2) switched off
# Import world map, dissolve/union polygons by continent, and add bubble lon/lat
# locations for plotting
continents <- ne_countries(returnclass='sf') %>%
  # Russia has incorrect continent value, so need to change it
  mutate(continent = ifelse(sovereignt == "Russia", "Asia", continent)) %>%
  group_by(continent) %>%
  summarise(geom = st_union(geometry)) %>%
  filter(!continent == "Seven seas (open ocean)") %>%
  mutate(centroid_lon = st_coordinates(st_centroid(.))[,1],
         centroid_lat = st_coordinates(st_centroid(.))[,2])
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
although coordinates are longitude/latitude, st_union assumes that they are planar
Warning: There were 4 warnings in `stopifnot()`.
The first warning was:
ℹ In argument: `centroid_lon = st_coordinates(st_centroid(.))[, 1]`.
Caused by warning:
! st_centroid assumes attributes are constant over geometries
ℹ Run ]8;;ide:run:dplyr::last_dplyr_warnings()dplyr::last_dplyr_warnings()]8;; to see the 3 remaining warnings.
# dataset calculation
location_dirty <- select(swu, location)

locations<- location_dirty %>%
  group_by(location) %>% 
  summarise(count = n())

colnames(locations) <- c("continent", "count")

# Join count data to continents
continents <- left_join(continents, locations, by = "continent")

# Plot
ggplot(data = continents) +
  geom_sf() +
  geom_point(aes(x = centroid_lon, y = centroid_lat, size = count, color = "red")) +
  scale_size(range = c(1, 10)) +
  labs(size = "Count", title = "Location distribution") +
  theme(axis.title = element_blank())


# It is a good habit to turn S2 back on after you are done
sf_use_s2(TRUE)
Spherical geometry (s2) switched on

Demographic relations

Age vs Gender

age_perc <- swu %>% 
  group_by(gender, age) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2)))
# Chart
ggplot(age_perc, aes(x = factor(gender), y = perc, fill = factor(age))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Gender", y = "Percent", fill = "age", title = 'Distribution of Age per Gender (%)', subtitle = 'Stacked bars version') +
  theme_minimal(base_size = 14) +
  geom_text(data = age_perc, aes(y = perc, label = ratio), position = position_stack(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Age groups"))

ggplot(data = age_perc) + 
  geom_bar(
    aes(x = gender, y = perc, fill = age, group = age), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = age),
    position = position_dodge(width = 1),
    vjust = -0.5, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Age per Gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = age_perc) + 
  geom_bar(
    aes(x = gender, y = count, fill = age, group = age), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = age),
    position = position_dodge(width = 1),
    vjust = -0.5, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Age per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Age vs Location

age_loc_perc <- swu %>% 
  group_by(location, age) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2)))
# Chart
ggplot(age_loc_perc, aes(x = factor(location), y = perc, fill = factor(age))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Location", y = "Percent", fill = "age", title = 'Distribution of Age per Location (%)', subtitle = 'Stacked bars version') +
  theme_minimal(base_size = 14) +
  geom_text(data = age_loc_perc, aes(y = perc, label = ratio), position = position_stack(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Age groups"))

ggplot(data = age_loc_perc) + 
  geom_bar(
    aes(x = location, y = perc, fill = age, group = age), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = age),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Age per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = age_loc_perc) + 
  geom_bar(
    aes(x = location, y = count, fill = age, group = age), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = age),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Age per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Gender vs Location

gender_loc_perc <- swu %>% 
  group_by(location, gender) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2)))
# Chart
ggplot(gender_loc_perc, aes(x = factor(location), y = perc, fill = factor(gender))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Location", y = "Percent", fill = "gender", title = 'Distribution of Gender per Location (%)', subtitle = 'Stacked bars version') +
  theme_minimal(base_size = 14) +
  geom_text(data = gender_loc_perc, aes(y = perc, label = ratio), position = position_stack(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Gender")) +
  theme(axis.text.x = element_text(angle = 45))

ggplot(data = gender_loc_perc) + 
  geom_bar(
    aes(x = location, y = count, fill = gender, group = gender), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = gender),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  guides(fill = guide_legend(title = "Gender")) +
  labs(x = "Location", y = "Count", title = "Distribution of Gender per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Establishing relations between variables

Periodicity

Periodicity vs Gender

We want to identify if there are a relation between the periodicity of a smartwatch and the user’s gender

periodicity_gender <- swu %>% 
  group_by(gender, periodicity) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(periodicity)
# Chart
ggplot(periodicity_gender, aes(x = factor(gender), y = perc*100, fill = factor(periodicity))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Gender", y = "Percent", fill = "periodicity", title = "Percentage distribution of Periodicity per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = periodicity_gender, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title="Periodicity"))

# Chart
ggplot(data = periodicity_gender) + 
  geom_bar(
    aes(x = gender, y = perc, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = periodicity),
    position = position_dodge(width = 1),
    vjust = -0.5, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Periodicity per Gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = periodicity_gender) + 
  geom_bar(
    aes(x = gender, y = count, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = periodicity),
    position = position_dodge(width = 1),
    vjust = -0.5, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Periodicity per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Periodicity vs Age

We want to identify if there are a relation between the periodicity of a smartwatch and the user’s age

periodicity_age <- swu %>% 
  group_by(age, periodicity) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(periodicity)
# Chart
ggplot(periodicity_age, aes(x = factor(age), y = perc*100, fill = factor(periodicity))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Age", y = "Percent", fill = "periodicity", title = "Percentage distribution of Periodicity per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = periodicity_age, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title="Periodicity"))

# Chart
ggplot(data = periodicity_age) + 
  geom_bar(
    aes(x = age, y = perc, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = perc, label = ratio, group = periodicity),
    position = position_dodge(width = 1),
    vjust = -0.5, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Age", y = "Percentage", title = "Distribution of Periodicity per Age (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = periodicity_age) + 
  geom_bar(
    aes(x = age, y = count, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = count, label = count, group = periodicity),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Age", y = "Count", title = "Distribution of Periodicity per Age (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Periodicity vs Location

We want to identify if there are a relation between the periodicity of a smartwatch and the user’s location

periodicity_location <- swu %>% 
  group_by(location, periodicity) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(periodicity)
# Chart
ggplot(periodicity_location, aes(x = factor(location), y = perc*100, fill = factor(periodicity))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Location", y = "Percent", fill = "periodicity", title = "Percentage distribution of Periodicity per Location") +
  theme_minimal(base_size = 14) +
  geom_text(data = periodicity_location, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title="Periodicity")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = periodicity_location) + 
  geom_bar(
    aes(x = location, y = perc, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = periodicity),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Periodicity per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = periodicity_location) + 
  geom_bar(
    aes(x = location, y = count, fill = periodicity, group = periodicity), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = periodicity),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Periodicity per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Brand vs Gender

We want to identify if there are a relation between the brand of a smartwatch and the user’s gender

brand_gender <- swu %>% 
  group_by(gender, brand) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(brand)
# Chart
ggplot(brand_gender, aes(x = factor(gender), y = perc * 100, fill = factor(brand))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Gender", y = "Percent", fill = "brand", title = "Percentage distribution of Brand per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = brand_gender, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title="Brand"))

# Chart
ggplot(data = brand_gender) + 
  geom_bar(
    aes(x = gender, y = perc, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = brand),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Brand per gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = brand_gender) + 
  geom_bar(
    aes(x = gender, y = count, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = brand),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Brand per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Brand vs Age

We want to identify if there are a relation between the brand of a smartwatch and the user’s age

brand_age <- swu %>% 
  group_by(age, brand) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(brand)
# Chart
ggplot(brand_age, aes(x = factor(age), y = perc * 100, fill = factor(brand))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Age", y = "Percent", fill = "brand", title = "Percentage distribution of Brand per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = brand_age, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Brand"))

# Chart
ggplot(data = brand_age) + 
  geom_bar(
    aes(x = age, y = perc, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = perc, label = ratio, group = brand),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Age", y = "Percentage", title = "Distribution of Brand per Age (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = brand_age) + 
  geom_bar(
    aes(x = age, y = count, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = count, label = count, group = brand),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Age", y = "Count", title = "Distribution of Brand per Age (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Brand vs Location

We want to identify if there are a relation between the brand of a smartwatch and the user’s location

brand_location <- swu %>% 
  group_by(location, brand) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(brand)
# Chart
ggplot(brand_location, aes(x = factor(location), y = perc * 100, fill = factor(brand))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Location", y = "Percent", fill = "brand", title = "Percentage distribution of Brand per Location") +
  theme_minimal(base_size = 14) +
  geom_text(data = brand_location, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Brand"))

# Chart
ggplot(data = brand_location) + 
  geom_bar(
    aes(x = location, y = perc, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = brand),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Brand per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = brand_location) + 
  geom_bar(
    aes(x = location, y = count, fill = brand, group = brand), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = brand),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Brand per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Usage

Usage vs Gender

We want to identify if there are a relation between the usage of a smartwatch and the user’s gender

gender_usage <- swu %>% 
  group_by(gender, usage) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>%
  drop_na(usage)
# Chart
ggplot(gender_usage, aes(x = factor(gender), y = perc * 100, fill = factor(usage))) +
  geom_bar(stat ="identity", width = 0.7, position = "fill") +
  labs(x = "Gender", y = "Percent", fill = "usage", title = "Percentage distribution of Usage per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = gender_usage, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title="Usage"))

# Chart
ggplot(data = gender_usage) + 
  geom_bar(
    aes(x = gender, y = perc, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = usage),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Usage per Gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = gender_usage) + 
  geom_bar(
    aes(x = gender, y = count, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = usage),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Usage per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Usage vs Age

We want to identify if there are a relation between the usage of a smartwatch and the user’s age

age_usage <- swu %>% 
  group_by(age, usage) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>%
  drop_na(usage)
# Chart
ggplot(age_usage, aes(x = factor(age), y = perc * 100, fill = factor(usage))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Age", y = "Percent", fill = "usage", title = "Percentage distribution of Usage per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = age_usage, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Usage")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = age_usage) + 
  geom_bar(
    aes(x = age, y = perc, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = perc, label = ratio, group = usage),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Age", y = "Percentage", title = "Distribution of Usage per Age (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = age_usage) + 
  geom_bar(
    aes(x = age, y = count, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = count, label = count, group = usage),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Age", y = "Count", title = "Distribution of Usage per Age (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Usage vs Location

We want to identify if there are a relation between the usage of a smartwatch and the user’s location

location_usage <- swu %>% 
  group_by(location, usage) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>%
  drop_na(usage)
# Chart
ggplot(location_usage, aes(x = factor(location), y = perc * 100, fill = factor(usage))) +
  geom_bar(stat="identity", width = 0.7, position = "fill") +
  labs(x = "Location", y = "Percent", fill = "usage", title = "Percentage distribution of Usage per Location") +
  theme_minimal(base_size = 14) +
  geom_text(data = location_usage, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill=guide_legend(title = "Usage")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = location_usage) + 
  geom_bar(
    aes(x = location, y = perc, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = usage),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Usage per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = location_usage) + 
  geom_bar(
    aes(x = location, y = count, fill = usage, group = usage), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = usage),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Usage per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Features

Features vs Gender

We want to identify if there are a relation between the used features of a smartwatch and the user’s gender.

gender_features <- features_grouped_rows %>% 
  group_by(gender, features_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>%
  drop_na(features_grouped)
# Chart
ggplot(gender_features, aes(x = factor(gender), y = perc * 100, fill = factor(features_grouped))) +
  geom_bar(stat = "identity", width = 0.7, position = "fill") +
  labs(x = "Gender", y = "Percent", fill = "features_grouped", title = "Percentage distribution of Features per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = gender_features, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Features"))

# Chart
ggplot(data = gender_features) + 
  geom_bar(
    aes(x = gender, y = perc, fill = features_grouped, group = features_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Features per Gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = gender_features) + 
  geom_bar(
    aes(x = gender, y = count, fill = features_grouped, group = features_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Features per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Features vs Age

We want to identify if there are a relation between the used features of a smartwatch and the user’s age.

age_features <- features_grouped_rows %>% 
  group_by(age, features_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(features_grouped)
# Chart
ggplot(age_features, aes(x = factor(age), y = perc * 100, fill = factor(features_grouped))) +
  geom_bar(stat = "identity", width = 0.7, position = "fill") +
  labs(x = "Age", y = "Percent", fill = "features_grouped", title = "Percentage distribution of Features per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = age_features, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Features")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = age_features) + 
  geom_bar(
    aes(x = age, y = perc, fill = features_grouped, group = features_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = perc, label = ratio, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Age", y = "Percentage", title = "Distribution of Features per Age (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = age_features) + 
  geom_bar(
    aes(x = age, y = count, fill = features_grouped, group = features_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = count, label = count, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Age", y = "Count", title = "Distribution of Features per Age (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Features vs Location

We want to identify if there are a relation between the features of a smartwatch and the user’s location

location_features <- features_grouped_rows %>% 
  group_by(location, features_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>%
  drop_na(features_grouped)
# Chart
ggplot(location_features, aes(x = factor(location), y = perc * 100, fill = factor(features_grouped))) +
  geom_bar(stat = "identity", width = 0.7, position = "fill") +
  labs(x = "Location", y = "Percent", fill = "features_grouped", title = "Percentage distribution of Features per Location") +
  theme_minimal(base_size = 14) +
  geom_text(data = location_features, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Features")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = location_features) + 
  geom_bar(
    aes(x = location, y = perc, fill = features_grouped, group = features_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Features per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = location_features) + 
  geom_bar(
    aes(x = location, y = count, fill = features_grouped, group = features_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = features_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Features per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Functionalities

Functionalities vs Gender

We want to identify if there are a relation between the functionalities of a smartwatch and the user’s gender.

gender_functionalities <- functionalities_grouped_rows %>% 
  group_by(gender, functionalities_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(functionalities_grouped)
# Chart
ggplot(gender_functionalities, aes(x = factor(gender), y = perc * 100, fill = factor(functionalities_grouped))) +
  geom_bar(stat = "identity", width = 0.7, position = "fill") +
  labs(x = "Gender", y = "Percent", fill = "functionalities_grouped", title = "Percentage distribution of Functionalities per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = gender_functionalities, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill = guide_legend(title = "Functionalities"))

# Chart
ggplot(data = gender_functionalities) + 
  geom_bar(
    aes(x = gender, y = perc, fill = functionalities_grouped, group = functionalities_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = perc, label = ratio, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Gender", y = "Percentage", title = "Distribution of Functionalities per Gender (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = gender_functionalities) + 
  geom_bar(
    aes(x = gender, y = count, fill = functionalities_grouped, group = functionalities_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ gender, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = gender, y = count, label = count, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Gender", y = "Count", title = "Distribution of Functionalities per Gender (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Functionalities vs Age

We want to identify if there are a relation between the tracked functionalities of a smartwatch per age.

age_functionalities <- functionalities_grouped_rows %>% 
  group_by(age, functionalities_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(functionalities_grouped)
# Chart
ggplot(age_functionalities, aes(x = factor(age), y = perc*100, fill = factor(functionalities_grouped))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Age", y = "Percent", fill = "functionalities_grouped", title = "Percentage distribution of Functionalities per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = age_functionalities, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill=guide_legend(title="Functionalities")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = age_functionalities) + 
  geom_bar(
    aes(x = age, y = perc, fill = functionalities_grouped, group = functionalities_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = perc, label = ratio, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Age", y = "Percentage", title = "Distribution of Functionalities per Age (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = age_functionalities) + 
  geom_bar(
    aes(x = age, y = count, fill = functionalities_grouped, group = functionalities_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ age, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = age, y = count, label = count, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Age", y = "Count", title = "Distribution of Functionalities per Age (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Functionalities vs Location

We want to identify if there are a relation between the functionalities of a smartwatch per and the user’s location

locacion_functionalities <- functionalities_grouped_rows %>% 
  group_by(location, functionalities_grouped) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(round(perc, 2))) %>% 
  drop_na(functionalities_grouped)
# Chart
ggplot(locacion_functionalities, aes(x = factor(location), y = perc*100, fill = factor(functionalities_grouped))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Location", y = "Percent", fill = "functionalities_grouped", title = "Percentage distribution of Functionalities per Location") +
  theme_minimal(base_size = 14) +
  geom_text(data = locacion_functionalities, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill=guide_legend(title="Functionalities")) +
  theme(axis.text.x = element_text(angle = 45))

# Chart
ggplot(data = locacion_functionalities) + 
  geom_bar(
    aes(x = location, y = perc, fill = functionalities_grouped, group = functionalities_grouped), 
    stat = 'identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = perc, label = ratio, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  labs(x = "Location", y = "Percentage", title = "Distribution of Functionalities per Location (%)", subtitle = "Grouped bars version") +
  theme_bw()

ggplot(data = locacion_functionalities) + 
  geom_bar(
    aes(x = location, y = count, fill = functionalities_grouped, group = functionalities_grouped), 
    stat='identity', position = 'dodge'
  ) +
  facet_wrap(~ location, scales = "free_x", drop = TRUE) +
  geom_text(
    aes(x = location, y = count, label = count, group = functionalities_grouped),
    position = position_dodge(width = 1),
    vjust = 0.1, size = 3
  ) +
  labs(x = "Location", y = "Count", title = "Distribution of Functionalities per Location (Count)", subtitle = "Grouped bars version") +
  theme_bw()

Activities

Activities vs Gender

We want to identify if there are a relation between the sport activities tracked by users per gender.

gender_activities <- activities_grouped_rows %>% 
  group_by(gender, activities) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(count/sum(count))) %>% 
  drop_na(activities)

# Chart
ggplot(gender_activities, aes(x = factor(gender), y = perc*100, fill = factor(activities))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Gender", y = "Percent", fill = "activities", title = "Percentage distribution of 'Activities' per Gender") +
  theme_minimal(base_size = 14) +
  geom_text(data = gender_activities, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill=guide_legend(title="Activities"))

Activities vs Age

We want to identify if there are a relation between the sport activities tracked by users per age

age_activities <- activities_grouped_rows %>% 
  group_by(age, activities) %>% 
  summarise(count = n()) %>% 
  mutate(perc = count/sum(count), ratio = scales::percent(count/sum(count))) %>% 
  drop_na(activities)

# Chart
ggplot(age_activities, aes(x = factor(age), y = perc*100, fill = factor(activities))) +
  geom_bar(stat="identity", width = 0.7, position="fill") +
  labs(x = "Age", y = "Percent", fill = "activities", title = "Percentage distribution of 'Activities' per Age") +
  theme_minimal(base_size = 14) +
  geom_text(data = age_activities, aes(y = count, label = ratio), position = position_fill(vjust = 0.5)) +
  scale_y_continuous(labels = scales::percent_format(accuracy = 5L)) +
  guides(fill=guide_legend(title="Activities")) +
  theme(axis.text.x = element_text(angle = 45))
LS0tCnRpdGxlOiAiU21hcnQgZGV2aWNlcyB1c2FnZSIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBDT05URVhUCgpCZWxsYWJpdCBpcyBhIGhpZ2gtdGVjaCBjb21wYW55IHRoYXQgbWFudWZhY3R1cmVzIGhlYWx0aC1mb2N1c2VkIHNtYXJ0IHByb2R1Y3RzIHNpbmNlIDIwMTMuIFRoZWlyIHByb2R1Y3RzOgoKKiAqKkJlbGxhYmVhdCBhcHAqKjogcHJvdmlkZXMgdXNlcnMgd2l0aCBoZWFsdGggZGF0YSByZWxhdGVkIHRvIHRoZWlyIGFjdGl2aXR5LCBzbGVlcCwgc3RyZXNzLAptZW5zdHJ1YWwgY3ljbGUsIGFuZCBtaW5kZnVsbmVzcyBoYWJpdHMuIEl0IGNvbm5lY3RzIHRvIHRoZWlyIGxpbmUgb2Ygc21hcnQgd2VsbG5lc3MgcHJvZHVjdHMuCiogKipMZWFmKio6IGEgd2VsbG5lc3MgdHJhY2tlciBjYW4gYmUgd29ybiBhcyBhIGJyYWNlbGV0LCBuZWNrbGFjZSwgb3IgY2xpcC4gSXQgY29ubmVjdHMgdG8gdGhlIEJlbGxhYmVhdCBhcHAgdG8gdHJhY2sgYWN0aXZpdHksIHNsZWVwLCBhbmQgc3RyZXNzLgoqICoqVGltZSoqOiBhIHdlbGxuZXNzIHdhdGNoIHRvIHRyYWNrIHVzZXIgYWN0aXZpdHksIHNsZWVwLCBhbmQgc3RyZXNzLiBJdCBjb25uZWN0cyB0byB0aGUgQmVsbGFiZWF0IGFwcCB0byBwcm92aWRlIGRhaWx5IHdlbGxuZXNzLgoqICoqU3ByaW5nKio6IGEgd2F0ZXIgYm90dGxlIHRoYXQgdHJhY2tzIGRhaWx5IHdhdGVyIGludGFrZSB0aGF0IGNvbm5lY3RzIHRvIHRoZSBCZWxsYWJlYXQgYXBwIHRvIHRyYWNrCmh5ZHJhdGlvbiBsZXZlbHMuCiogKipCZWxsYWJlYXQgbWVtYmVyc2hpcCoqOiBhIHN1YnNjcmlwdGlvbi1iYXNlZCBtZW1iZXJzaGlwIHByb2dyYW0gZm9yIHVzZXJzIHRoYXQgZ2l2ZXMgMjQvNyBhY2Nlc3MgdG8gZnVsbHkgcGVyc29uYWxpemVkIGd1aWRhbmNlIG9uIG51dHJpdGlvbiwgYWN0aXZpdHksIHNsZWVwLCBoZWFsdGggYW5kIGJlYXV0eSwgYW5kIG1pbmRmdWxuZXNzIGJhc2VkIG9uIHRoZWlyIGxpZmVzdHlsZSBhbmQgZ29hbHMuCgpCZWxsYWJlYXQgd2FudHMgdG8gZ2V0IGluc2lnaHRzIGFib3V0IHRoZSBzbWFydCBkZXZpY2VzIHVzYWdlIGluIG9yZGVyIHRvIG9idGFpbiB0cmVuZHMgdGhhdCBoZWxwIHRoZWlyIG1hcmtldGluZyBzdHJhdGVneS4KCiMgQVNLCgojIyBCdXNpbmVzcyB0YXNrCkFuYWx5emUgc21hcnQgZGV2aWNlIHVzYWdlIHRvIGdhaW4gaW5zaWdodHMgaW50byBob3cgcGVvcGxlIGFyZSBhbHJlYWR5IHVzaW5nIHRoZWlyIHNtYXJ0IGRldmljZXMgYW5kIHByb3ZpZGUgaGlnaC1sZXZlbCByZWNvbW1lbmRhdGlvbnMgdG8gaW1wcm92ZSBtYXJrZXRpbmcgc3RyYXRlZ2llcyBmb3IgQmVsbGFiZWF0LgoKIyMgQnVzaW5lc3MgdXNlIGNhc2UKKiBEZXRlcm1pbmUgdHJlbmRzIGZvciBzbWFydCBkZXZpY2UgdXNhZ2UKKiBIb3cgY291bGQgdGhlc2UgdHJlbmRzIGFwcGx5IHRvIEJlbGxhYmVhdCAnVGltZScgY3VzdG9tZXJzPwoqIEhvdyBjb3VsZCB0aGVzZSB0cmVuZHMgaGVscCB0byBpbXByb3ZlIEJlbGxhYmVhdCdzIG1hcmtldGluZyBzdHJhdGVneT8KCiMgUFJFUEFSRQpGb3IgdGhlIGFuYWx5c2lzLCBJIHdpbGwgdXNlIGEgY3VzdG9tIHN1cnZleSAoRmlyc3QtcGFydHkgZGF0YSkgaW4gb3JkZXIgdG8gZ2V0IHVwZGF0ZWQgZGF0YSByZWxhdGVkIHRvIHNtYXJ0d2F0Y2ggdXNhZ2VzLCBhbmQgdXNlIFIgd2l0aCBSU3R1ZGlvIHRvIHBlcmZvcm0gdGhlIGFuYWx5c2lzIHRhc2suCgojIyBCdWlsZGluZyB0aGUgc3VydmV5CiMjIyBQbGF0Zm9ybQpCdWlsZCBpbiBHb29nbGUgRm9ybXMgYW5kIGF2YWlsYWJsZSBpbiAyIGxhbmd1YWdlczogRW5nbGlzaCBhbmQgU3BhbmlzaC4gCiMjIyBEaXN0cmlidXRpb24KRGlzdHJpYnV0ZWQgdHJvdWdoIGEgbGluayB1c2luZyBMaW5rZWRJbiBwb3N0LCBJbnN0YWdyYW0gc3RvcmllcyBhbmQgV2hhdHNhcHAgZ3JvdXBzLiBObyByZXN0cmljdGlvbnMgdG8gc2hhcmUgdGhlIGxpbmsuCiMjIyBUaW1lIGZyYW1lCkF2YWlsYWJsZSBmb3IgNyBkYXlzLCBzdGFydGluZyBvbiAwMS8yNi8yMDI0CiMjIyBDb25maWd1cmF0aW9uCkFub255bW91cyBzdXJ2ZXkKIyMjIFF1ZXN0aW9ucwojIyMjIERlbW9ncmFwaGljIHF1ZXN0aW9ucwoqIEdlbmRlcgoqIEFnZQoqIEdlb2dyYXBoaWMgbG9jYXRpb24KCiMjIyMgU21hcnR3YXRjaCB1c2FnZSBxdWVzdGlvbnMKKiBNYWluIHVzYWdlOiBtdWx0aXBsZSBjaG9pY2UsIHdpdGggdGhlIG9wdGlvbiB0byBhZGQgYSBjdXN0b20gYW5zd2VyCiogVXNhZ2UgcGVyaW9kaWNpdHk6IHNjYWxlIGZyb20gMCB0byA3IHJlcHJlc2VudGluZyB1c2FnZSBpbiBkYXlzCiogQnJhbmQ6IG11bHRpcGxlIGNob2ljZSwgbGlzdGluZyBtYWluIGJyYW5kIGNvbGxlY3RlZCBmcm9tIHNpdGVzIGxpa2UgQW1hem9uLCBUaWVuZGFtaWEsIE1lcmNhZG8gTGlicmUuIE9wdGlvbiBmb3IgYWRkIGN1c3RvbSBhbnN3ZXIuCiogRmVhdHVyZXMgdXNlZDogY2hlY2tib3hzLCBsaXN0aW5nIG1haW4gZmVhdHVyZXMgb2ZmZXJlZCBieSBzbWFydHdhdGNoZXMgb24gdGhlIG1hcmtldC4gT3B0aW9uIGZvciBhZGQgY3VzdG9tIGFuc3dlci4KKiBUcmFja2VkIGZ1bmN0aW9uYWxpdGllczogY2hlY2tib3hzLCBsaXN0aW5nIG1haW4gdHJhY2tlciBvcHRpb25zIG9mZmVycyB0aGUgc21hcnR3YXRjaGVzIG9uIHRoZSBtYXJrZXQuIE9wdGlvbiBmb3IgYWRkIGN1c3RvbSBhbnN3ZXIuCiogQWN0aXZpdGllcyB0cmFja2VkOiBjaGVja2JveHMsIGxpc3RpbmcgbWFpbiBzcG9ydCBhY3Rpdml0aWVzIHRyYWNrZWQgZm9yIHRoZSBzbWFydHdhdGNoZXMgb24gdGhlIG1hcmtldC4gT3B0aW9uIGZvciBhZGQgY3VzdG9tIGFuc3dlci4KCiMjIEV2YWx1YXRpbmcgZGF0YQpJbnN0YWxsaW5nIHBhY2thZ2VzCmBgYHtyIEluc3RhbGxpbmcgcGFja2FnZXMsIGVjaG89RkFMU0V9Cmluc3RhbGwucGFja2FnZXMoYygidGlkeXZlcnNlIiwgImRwbHlyIiwgInNraW1yIikpCmluc3RhbGwucGFja2FnZXMoImphbml0b3IiKQppbnN0YWxsLnBhY2thZ2VzKCJnZ2hpZ2hsaWdodCIpCmluc3RhbGwucGFja2FnZXMoInRpZHl0ZXh0IikKaW5zdGFsbC5wYWNrYWdlcygicm5hdHVyYWxlYXJ0aCIpCmluc3RhbGwucGFja2FnZXMoInNmIikKaW5zdGFsbC5wYWNrYWdlcygiZm9yY2F0cyIpCgpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShza2ltcikKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KGdnaGlnaGxpZ2h0KQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHNmKSAjIEZvciBzcGF0aWFsIGRhdGEKbGlicmFyeShybmF0dXJhbGVhcnRoKSAjIEZvciBtYXAgZGF0YQpsaWJyYXJ5KGZvcmNhdHMpCmBgYAoKIyMgSW1wb3J0aW5nIGRhdGEKV2UgbmVlZCB0byBpbXBvcnQgYm90aCBzdXJ2ZXkgZmlsZXMsIHRoZSBFbmdsaXNoIGFuZCB0aGUgU3BhbmlzaCB2ZXJzaW9uCmBgYHtyIEltcG9ydGluZyBzdXJ2ZXkgZmlsZXMsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnN3dV9maWxlX2VuIDwtIHJlYWRfY3N2KCJTbWFydHdhdGNoIHVzYWdlIC0gZW5nbGlzaC5jc3YiKQpzd3VfZmlsZV9lcyA8LSByZWFkX2NzdigiU21hcnR3YXRjaCB1c2FnZSAtIFNwYW5pc2guY3N2IikKYGBgCgojIyMgR2V0IHByZXZpZXcgb2YgaW1wb3J0ZWQgZGF0YQpXZSBuZWVkIHRvIGNoZWNrIGlmIHRoZXJlIGlzIGFueSBlcnJvciBpbXBvcnRpbmcgdGhlIGZpbGVzCmBgYHtyfQpoZWFkKHN3dV9maWxlX2VuKQpoZWFkKHN3dV9maWxlX2VzKQpgYGAKCiMjIyBDaGFuZ2luZyBjb2x1bW4gbmFtZXMgZm9yIGJvdGggZmlsZXMKRXZlcnkgZmlsZSBoYXMgZGlmZmVyZW50IGNvbHVtbiBuYW1lcyBiZWNhdXNlIHRoZXkgd2VyZSBzaGFyZWQgaW4gZGlmZmVyZW50IGxhbmd1YWdlcywgdGhvdWdoIHRoZXkgc2hvdyB0aGUgc2FtZSBpbmZvcm1hdGlvbgpgYGB7ciBDaGFuZ2luZyBjb2x1bW4gbmFtZXN9CnN3dV9lcyA8LSByZW5hbWUoc3d1X2ZpbGVfZXMsIAogICAgICAgJ2dlbmRlcl9kaXJ0eScgPSAnwr9Db24gcXXDqSBnZW5lcm8gdGUgaWRlbnRpZmljYXM/JywKICAgICAgICdhZ2VfZGlydHknID0gJ8K/UXXDqSBlZGFkIHRlbsOpcz8nLAogICAgICAgJ2xvY2F0aW9uX2RpcnR5JyA9ICfCv0TDs25kZSB2aXbDrXM/JywKICAgICAgICd1c2FnZV9kaXJ0eScgPSAnwr9DdcOhbCBlcyBlbCBwcmluY2lwYWwgdXNvIHF1ZSBsZSBkYXMgYSB0dSByZWxvaiBpbnRlbGlnZW50ZT8nLAogICAgICAgJ3BlcmlvZGljaXR5JyA9ICfCv0N1w6FudG9zIGTDrWFzIHV0aWxpemFzIGFsZ3VuYSBmdW5jaW9uYWxpZGFkIGRlIHR1IHJlbG9qIGludGVsaWdlbnRlPycsCiAgICAgICAnYnJhbmRfZGlydHknID0gJ8K/Q3XDoWwgZXMgbGEgbWFyY2EgZGUgdHUgcmVsb2ogaW50ZWxpZ2VudGU/JywKICAgICAgICdmZWF0dXJlc19kaXJ0eScgPSAnwr9DdcOhbGVzIHNvbiBsYXMgZnVuY2lvbmVzIHF1ZSB1dGlsaXphcyBlbiB0dSByZWxvaiBpbnRlbGlnZW50ZT8nLAogICAgICAgJ2Z1bmN0aW9uYWxpdGllc19kaXJ0eScgPSAnwr9RdcOpIGZ1bmNpb25lcyB1dGlsaXphcyBwYXJhIHJlYWxpemFyIHVuIHNlZ3VpbWllbnRvIGNvbiB0dSByZWxvaiBpbnRlbGlnZW50ZT8nLAogICAgICAgJ2FjdGl2aXRpZXNfZGlydHknID0gJ8K/UXXDqSBhY3RpdmlkYWRlcyBkZXBvcnRpdmFzIHNlZ3XDrXMgY29uIHR1IHJlbG9qIGludGVsaWdlbnRlPycKICAgICAgICkKCnN3dV9lbiA8LSByZW5hbWUoc3d1X2ZpbGVfZW4sIAogICAgICAgJ2dlbmRlcl9kaXJ0eScgPSAnV2hhdCBnZW5kZXIgZG8geW91IGlkZW50aWZ5IHdpdGg/JywKICAgICAgICdhZ2VfZGlydHknID0gJ0hvdyBvbGQgYXJlIHlvdT8nLAogICAgICAgJ2xvY2F0aW9uX2RpcnR5JyA9ICdXaGVyZSBkbyB5b3UgbGl2ZT8nLAogICAgICAgJ3VzYWdlX2RpcnR5JyA9ICdXaGljaCBpcyB0aGUgbWFpbiB1c2UgeW91IGdpdmUgdG8geW91ciBzbWFydHdhdGNoPycsCiAgICAgICAncGVyaW9kaWNpdHknID0gJ0hvdyBtYW55IGRheXMgZG8geW91IHVzZSBhbnkgZnVuY3Rpb25hbGl0eSBvZiB5b3VyIHNtYXJ0d2F0Y2g/JywKICAgICAgICdicmFuZF9kaXJ0eScgPSAnV2hpY2ggaXMgdGhlIGJyYW5kIG9mIHlvdXIgc21hcnR3YXRjaD8nLAogICAgICAgJ2ZlYXR1cmVzX2RpcnR5JyA9ICdXaGF0IGFyZSB0aGUgZmVhdHVyZXMgeW91IHVzZSBvbiB5b3VyIHNtYXJ0d2F0Y2g/JywKICAgICAgICdmdW5jdGlvbmFsaXRpZXNfZGlydHknID0gJ1doYXQgZmVhdHVyZXMgZG8geW91IHVzZSB0byB0cmFjayB3aXRoIHlvdXIgc21hcnR3YXRjaD8nLAogICAgICAgJ2FjdGl2aXRpZXNfZGlydHknID0gJ1doYXQgc3BvcnQgYWN0aXZpdGllcyBkbyB5b3UgdHJhY2sgd2l0aCB5b3VyIHNtYXJ0d2F0Y2g/JwogICAgICAgKQpgYGAKCiMjIyBCaW5kaW5nIGZpbGVzCldlIG5lZWQgdG8gZ2V0IG9uZSBmaWxlIHRvIHByb2Nlc3MgdGhlIGluZm9ybWF0aW9uCmBgYHtyIEJpbmRpbmcgZmlsZXMgaW50byBvbmUgbGFycXFyZ2VyIGZpbGV9CnN3dV9kaXJ0eSA8LSB1bmlvbihzd3VfZXMsIHN3dV9lbikKYGBgCgojIyMgQ2hlY2tpbmcgcmVzdWx0aW5nIGRhdGFmcmFtZQpUaGUgcmVzdWx0aW5nIGRhdGFmcmFtZSBzaG91bGQgaGF2ZSB0aGUgc3VtIG9mIHJvd3Mgb2YgYm90aCBmaWxlcwpgYGB7ciBDaGVja2luZyByZXN1bHRpbmcgZGF0YWZyYW1lfQpza2ltX3dpdGhvdXRfY2hhcnRzKHN3dV9kaXJ0eSkKYGBgCgojIFBST0NFU1MKIyMgUHJlcGFyaW5nIGVudmlyb25tZW50IGZvciBjbGVhbmluZyBkYXRhCgojIyMgR2VuZXJhbCBjbGVhbmluZwpXZSBwZXJmb3JtIGEgZ2VuZXJhbCBjbGVhbmluZyBvbiB0aGUgZGF0YToKKiBjbGVhciBuYW1lcyAodG8gc25ha2VfY2FzZSkKKiByZW1vdmUgZW1wdHkgdmFsdWVzCmBgYHtyIFJ1bm5pbmcgZ2VuZXJhbCBjbGVhbmluZ30Kc3d1IDwtIHN3dV9kaXJ0eSAlPiUgY2xlYW5fbmFtZXMoKSAlPiUgcmVtb3ZlX2VtcHR5KGMoInJvd3MiLCAiY29scyIpKQpgYGAKCiMjIyBUcmFuc2xhdGluZyBmaWVsZHMKQXMgd2Ugc2hhcmUgdGhlIHN1cnZleSBpbiAyIGxhbmd1YWdlcyAoRW5nbGlzaCBhbmQgU3BhbmlzaCksIG1hbnkgb2YgdGhlIGFuc3dlcnMgbmVlZCB0byBiZSB1bmlmaWVkIHRvIGNvdW50IGFzIG9uZSB0eXBlIG9mIGFuc3dlcgoKIyMgQ2xlYW5pbmcgY29sdW1ucwoKIyMjIEdlbmRlcgpgYGB7ciBDaGVjayBmb3IgZGlzdGluY3QgdmFsdWVzIGluIGdlbmRlciBjb2x1bW59CnVuaXF1ZShzd3VbJ2dlbmRlcl9kaXJ0eSddKQpgYGAKCmBgYHtyIENyZWF0aW5nIGEgbmV3IGNvbHVtbiB3aXRoIG11dGF0ZWQgdmFsdWVzIGluIEVuZ2xpc2ggZm9yIGdlbmRlcn0Kc3d1IDwtIG11dGF0ZShzd3UsIGdlbmRlciA9IGNhc2Vfd2hlbigKICBnZW5kZXJfZGlydHkgPT0gJ01hc2N1bGlubycgfiAnTWFsZScsCiAgZ2VuZGVyX2RpcnR5ID09ICdGZW1lbmlubycgfiAnRmVtYWxlJywKICBnZW5kZXJfZGlydHkgPT0gJ1ByZWZpZXJvIG5vIGRlY2lyJyB+ICdQcmVmZXIgbm90IHRvIHNheScsCiAgVFJVRSB+IGdlbmRlcl9kaXJ0eQopKQp1bmlxdWUoc3d1WydnZW5kZXInXSkKYGBgCgojIyMgQWdlCmBgYHtyIENoZWNrIGZvciBkaXN0aW5jdCB2YWx1ZXMgaW4gYWdlIGNvbHVtbn0KdW5pcXVlKHN3dVsnYWdlX2RpcnR5J10pCmBgYAoKYGBge3IgQ3JlYXRpbmcgYSBuZXcgY29sdW1uIHdpdGggbXV0YXRlZCB2YWx1ZXMgaW4gRW5nbGlzaCBmb3IgYWdlfQpzd3UgPC0gbXV0YXRlKHN3dSwgYWdlID0gY2FzZV93aGVuKAogIGFnZV9kaXJ0eSA9PSAnTcOhcyBkZSA2NicgfiAnTW9yZSB0aGFuIDY2JywKICBUUlVFIH4gYWdlX2RpcnR5CikpCnVuaXF1ZShzd3VbJ2FnZSddKQpgYGAKCiMjIyBVc2VyIGxvY2F0aW9uCmBgYHtyIENoZWNrIGZvciBkaXN0aW5jdCB2YWx1ZXMgaW4gdXNlcl9sb2NhdGlvbiBjb2x1bW59CnVuaXF1ZShzd3VbJ2xvY2F0aW9uX2RpcnR5J10pCmBgYAoKYGBge3IgQ3JlYXRpbmcgYSBuZXcgY29sdW1uIHdpdGggbXV0YXRlZCB2YWx1ZXMgaW4gRW5nbGlzaCBmb3IgdXNlcl9sb2NhdGlvbn0Kc3d1IDwtIG11dGF0ZShzd3UsIGxvY2F0aW9uID0gY2FzZV93aGVuKAogIGxvY2F0aW9uX2RpcnR5ID09ICdOb3J0ZWFtw6lyaWNhJyB+ICdOb3J0aCBBbWVyaWNhJywKICBsb2NhdGlvbl9kaXJ0eSA9PSAnQW3DqXJpY2EgQ2VudHJhbCB5IFN1ZGFtw6lyaWNhJyB+ICdTb3V0aCBBbWVyaWNhJywKICBsb2NhdGlvbl9kaXJ0eSA9PSAnQ2VudHJhbCBhbmQgU291dGggQW1lcmljYScgfiAnU291dGggQW1lcmljYScsCiAgbG9jYXRpb25fZGlydHkgPT0gJ0V1cm9wYScgfiAnRXVyb3BlJywKICBsb2NhdGlvbl9kaXJ0eSA9PSAnw4FmcmljYScgfiAnQWZyaWNhJywKICBsb2NhdGlvbl9kaXJ0eSA9PSAnT2NlYW7DrWEnIH4gJ0F1c3RyYWxpYScsCiAgVFJVRSB+IGxvY2F0aW9uX2RpcnR5CikpCnVuaXF1ZShzd3VbJ2xvY2F0aW9uJ10pCmBgYAoKIyMjIE1haW4gdXNhZ2UKYGBge3IgQ2hlY2sgZm9yIGRpc3RpbmN0IHZhbHVlcyBpbiBtYWluX3VzYWdlIGNvbHVtbn0KdW5pcXVlKHN3dVsndXNhZ2VfZGlydHknXSkKYGBgCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBjb2x1bW4gd2l0aCBtdXRhdGVkIHZhbHVlcyBpbiBFbmdsaXNoIGZvciB1c2FnZV9kaXJ0eX0Kc3d1IDwtIG11dGF0ZShzd3UsIHVzYWdlID0gY2FzZV93aGVuKAogIAogIGdyZXBsKCcoP2kpZW50cmVuYW1pZW50b3woP2kpdHJhaW5pbmcnLCB1c2FnZV9kaXJ0eSkgfiAnVHJhaW5pbmcgdHJhY2tlcicsCiAgZ3JlcGwoJyg/aSljZWx1bGFyfCg/aSljZWxsfCg/aSlub3RpZmljYXRpb24nLCB1c2FnZV9kaXJ0eSkgfiAnU2hvcnRjdXQgdG8gY2VsbCcsCiAgZ3JlcGwoJyg/aSlzYWx1ZHwoP2kpaGVhbHRoJywgdXNhZ2VfZGlydHkpIH4gJ0hlYWx0aCB0cmFja2VyJywKICAKICAjICdPdGhlcicgb3B0aW9ucyBsaXN0ZWQgYmVsb3cKICBncmVwbCgnKD9pKW9wY2lvbmVzfCg/aSlvcHRpb25zJywgdXNhZ2VfZGlydHkpIH4gJ0FsbCBvcHRpb25zJywKICBncmVwbCgnKD9pKWhvcmF8KD9pKXJlbG9qfCg/aSl0aW1lfCg/aSl3YXRjaCcsIHVzYWdlX2RpcnR5KSB+ICdXYXRjaCB1c2FnZScsCiAgZ3JlcGwoJyg/aSlwYWdvfCg/aSlwYXl8KD9pKXBheW1lbnQnLCB1c2FnZV9kaXJ0eSkgfiAnUGF5bWVudHMnLAogIAogIFRSVUUgfiB1c2FnZV9kaXJ0eQopKQp1bmlxdWUoc3d1Wyd1c2FnZSddKQpgYGAKCiMjIyBCcmFuZApgYGB7ciBDaGVjayBmb3IgZGlzdGluY3QgdmFsdWVzIGluIGJyYW5kIGNvbHVtbn0KdW5pcXVlKHN3dVsnYnJhbmRfZGlydHknXSkKYGBgCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBjb2x1bW4gd2l0aCBtdXRhdGVkIHZhbHVlcyBpbiBFbmdsaXNoIGZvciBicmFuZH0Kc3d1IDwtIG11dGF0ZShzd3UsIGJyYW5kID0gY2FzZV93aGVuKAogIAogIGdyZXBsKCdJIGhhdmUgU2Ftc3VuZyBhbmQgQ29sbWkuIE5vdyBJIHVzZSBDb2xtaScsIGJyYW5kX2RpcnR5KSB+ICdDb2xtaScsCiAgZ3JlcGwoJyg/aSlTdXVudG8nLCBicmFuZF9kaXJ0eSkgfiAnU3V1bnRvJywKICBncmVwbCgnU2lucmVsb2ppbnRlbGlnZW50fCg/aSl4eHgnLCBicmFuZF9kaXJ0eSkgfiBOQSwKICAKICBUUlVFIH4gYnJhbmRfZGlydHkKKSkKdW5pcXVlKHN3dVsnYnJhbmQnXSkKYGBgCgojIyBHcm91cCBieSBkZW1vZ3JhcGhpYyBmaWVsZHMgCldlIG5lZWQgdG8gY3JlYXRlIG5ldyBkYXRhIGZyYW1lcyBmb3IgZXZlcnkgbXVsdGlwbGUtdmFsdWUgY29sdW1ucyBhbG9uZyB3aXRoIGRlbW9ncmFwaGljIGZpZWxkcyBmb3IgaW5kaXZpZHVhbCBhbmFseXNpcwoKIyMjIEZlYXR1cmVzCidGZWF0dXJlcycgaXMgYSBxdWVzdGlvbiBmb3Iga25vd2luZyB3aGljaCBhcmUgdGhlIGNvbW1vbiB1c2VzIHRoYXQgYW4gdXNlciBnaXZlcyB0byB0aGVpciBzbWFydHdhdGNoIGFzIGEgZGV2aWNlLiAgClRoZSB1c2VycyBzaG91bGQgbWFyayBhcyBtYW55IGZlYXR1cmVzIGFzIHRoZXkgdXNlZCBvbiB0aGVpciBzbWFydHdhdGNoZXMuIFNvLCB3ZSBuZWVkIHRvIHNwbGl0IGFsbCB0aGlzIGNoZWNrZWQgb3B0aW9ucyBpbnRvIGRpZmZlcmVudCByb3dzIHRvIHByb2Nlc3MgdGhlbSB0aGF0IHdheS4gCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBkYXRhc2V0IGZvciBmZWF0dXJlc30KICBmZWF0dXJlc19kaXJ0eSA8LSBzZWxlY3Qoc3d1LCB0aW1lc3RhbXAsIGdlbmRlciwgYWdlLCBsb2NhdGlvbiwgcGVyaW9kaWNpdHksIGJyYW5kLCBmZWF0dXJlc19kaXJ0eSkKYGBgCgpgYGB7ciBTcGxpdGluZyBmZWF0dXJlcyBpbiBkaWZmZXJlbnQgcm93c30KICBmZWF0dXJlc19yb3dzIDwtIHNlcGFyYXRlX2xvbmdlcl9kZWxpbShmZWF0dXJlc19kaXJ0eSwgZmVhdHVyZXNfZGlydHksICcsICcpCmBgYAoKYGBge3IgQ2hlY2sgZm9yIGRpc3RpbmN0IHZhbHVlcyBpbiBmZWF0dXJlcyBjb2x1bW59CnVuaXF1ZShmZWF0dXJlc19yb3dzWydmZWF0dXJlc19kaXJ0eSddKQpgYGAKCldlIHdpbGwgY3JlYXRlIHR3byBkaWZmZXJlbnQgY29sdW1ucyBmb3IgZmVhdHVyZXMsIHRoZSBmaXJzdCBpcyB0byB0cmFuc2xhdGUgdGhlIHZhbHVlcyBhbmQgdGhlIHNlY29uZCBvbmUgdG8gZ3JvdXAgdGhlbSBpbnRvIGEgYmlnZ2VyIGNhdGVnb3J5CmBgYHtyIENyZWF0aW5nIGEgbmV3IGNvbHVtbiB3aXRoIG11dGF0ZWQgdmFsdWVzIGluIEVuZ2xpc2ggZm9yIGZlYXR1cmVzfQpmZWF0dXJlc19yb3dzIDwtIG11dGF0ZShmZWF0dXJlc19yb3dzLCBmZWF0dXJlcyA9IGNhc2Vfd2hlbigKICBncmVwbCgnKD9pKWRlcG9ydGV8KD9pKXNwb3J0fCg/aSlwYXNvcycsIGZlYXR1cmVzX2RpcnR5KSB+ICdTcG9ydHMgbW9uaXRvcicsCiAgZ3JlcGwoJyg/aSlhbGFybWF8KD9pKWFsYXJtJywgZmVhdHVyZXNfZGlydHkpIH4gJ0FsYXJtJywKICBncmVwbCgnKD9pKXNlZGVudGFyeXwoP2kpc2VkZW50YXJpc21vJywgZmVhdHVyZXNfZGlydHkpIH4gJ1NlZGVudGFyeSByZW1pbmRlcicsCiAgZ3JlcGwoJyg/aSlhZ3VhfCg/aSl3YXRlcicsIGZlYXR1cmVzX2RpcnR5KSB+ICdXYXRlciBkcmluayByZW1pbmRlcicsCiAgZ3JlcGwoJyg/aSlub3RpZmljYWNpb25lc3woP2kpbm90aWZpY2F0aW9ucycsIGZlYXR1cmVzX2RpcnR5KSB+ICdDZWxsIG5vdGlmaWNhdGlvbnMnLAogIGdyZXBsKCcoP2kpc2xhY2t8KD9pKXRleHQnLCBmZWF0dXJlc19kaXJ0eSkgfiAnVGV4dCBtZXNzYWdlcycsCiAgZ3JlcGwoJyg/aSljYWxlbmRhcicsIGZlYXR1cmVzX2RpcnR5KSB+ICdDYWxlbmRhcicsCiAgZ3JlcGwoJyg/aSltw7pzaWNhJywgZmVhdHVyZXNfZGlydHkpIH4gJ011c2ljJywKICBncmVwbCgnKD9pKWPDoW1hcmF8KD9pKWNhbWFyYScsIGZlYXR1cmVzX2RpcnR5KSB+ICdDYW1hcmEnLAogIGdyZXBsKCcoP2kpdGVsw6lmb25vfCg/aSl0ZWxlZsOzbmljYXMnLCBmZWF0dXJlc19kaXJ0eSkgfiAnUGhvbmUgY2FsbHMnLAogIGdyZXBsKCcoP2kpdm96JywgZmVhdHVyZXNfZGlydHkpIH4gJ1ZvaWNlIGNvbnRyb2wnLAogIGdyZXBsKCcoP2kpaG9yYXwoP2kpdGltZXwoP2kpd2F0Y2gnLCBmZWF0dXJlc19kaXJ0eSkgfiAnV2F0Y2gnLAogIGdyZXBsKCcoP2kpcGFnbycsIGZlYXR1cmVzX2RpcnR5KSB+ICdDb250YWN0bGVzcyBwYXltZW50cycsCiAgZ3JlcGwoJyg/aSljYWxvcsOtYXN8KD9pKXNhbHVkfCg/aSllc3RyZXN8KD9pKXN1ZcOxb3woP2kpcHJlc2lvbnwoP2kpY2FyZGlhY2EnLCBmZWF0dXJlc19kaXJ0eSkgfiAnSGVhbHRoIG1vbml0b3InLAogIGdyZXBsKCcoP2kpY2xpbWF8KD9pKWF0bW9zZmVyaWNvc3woP2kpd2VhdGhlcicsIGZlYXR1cmVzX2RpcnR5KSB+ICdXZWF0aGVyIG1vbml0b3InLAogIAogIFRSVUUgfiBmZWF0dXJlc19kaXJ0eQopKQp1bmlxdWUoZmVhdHVyZXNfcm93c1snZmVhdHVyZXMnXSkKYGBgCgoKYGBge3IgQ3JlYXRpbmcgYSBuZXcgY29sdW1uIHdpdGggbXV0YXRlZCB2YWx1ZXMgaW4gRW5nbGlzaCBmb3IgZmVhdHVyZXMgZ3JvdXBlZCBieSBjYXRlZ29yaWVzfQpmZWF0dXJlc19ncm91cGVkX3Jvd3MgPC0gbXV0YXRlKGZlYXR1cmVzX3Jvd3MsIGZlYXR1cmVzX2dyb3VwZWQgPSBjYXNlX3doZW4oCiAgZ3JlcGwoJyg/aSlzcG9ydHN8KD9pKXNwb3J0JywgZmVhdHVyZXMpIH4gJ1Nwb3J0cyBtb25pdG9yJywKICBncmVwbCgnKD9pKWFsYXJtfCg/aSlzZWRlbnRhcnl8KD9pKXdhdGVyJywgZmVhdHVyZXMpIH4gJ0FjdGl2aXR5IHJlbWluZGVyJywKICBncmVwbCgnKD9pKW5vdGlmaWNhdGlvbnN8KD9pKXRleHR8KD9pKWVtYWlsfCg/aSljYWxlbmRhcicsIGZlYXR1cmVzKSB+ICdDZWxsIG5vdGlmaWNhdGlvbnMnLAogIGdyZXBsKCcoP2kpbXVzaWN8KD9pKWNhbWFyYXwoP2kpcGhvbmV8KD9pKXZvaWNlJywgZmVhdHVyZXMpIH4gJ0NlbGwgY29udHJvbCcsCiAgZ3JlcGwoJyg/aSl0aW1lfCg/aSl3YXRjaCcsIGZlYXR1cmVzKSB+ICdXYXRjaCcsCiAgZ3JlcGwoJyg/aSlwYXltZW50fCg/aSlTT1N8KD9pKUdQUycsIGZlYXR1cmVzKSB+ICdPdGhlciBmZWF0dXJlcycsCiAgZ3JlcGwoJyg/aSljYWxvcmllc3woP2kpc3RyZXNzfCg/aSlzbGVlcHwoP2kpcHJlc2lvbnwoP2kpY2FyZGlhYycsIGZlYXR1cmVzKSB+ICdIZWFsdGggbW9uaXRvcicsCiAgZ3JlcGwoJyg/aSl3ZWF0aGVyJywgZmVhdHVyZXMpIH4gJ1dlYXRoZXIgbW9uaXRvcicsCiAgCiAgVFJVRSB+IGZlYXR1cmVzCikpCnVuaXF1ZShmZWF0dXJlc19ncm91cGVkX3Jvd3NbJ2ZlYXR1cmVzX2dyb3VwZWQnXSkKYGBgCiAKIyMjIFRyYWNrZWQgZnVuY3Rpb25hbGl0aWVzCid0cmFja2VkX2Z1bmN0aW9uYWxpdGllcycgaXMgYSBxdWVzdGlvbiB0byBkZXRlcm1pbmUgd2hpY2ggYXJlIHRoZSBmZWF0dXJlcyB0cmFja2VkIGJ5IHRoZSB1c2VycyB0aHJvdWdoIHRoZWlyIHNtYXJ0d2F0Y2hlcy4gVGhlIHVzZXJzIHNob3VsZCBtYXJrIGFzIG1hbnkgZmVhdHVyZXMgYXMgdGhleSB0cmFjayBvbiB0aGVpciBzbWFydHdhdGNoZXMuIFNvLCB3ZSBuZWVkIHRvIHNwbGl0IGFsbCB0aGlzIGNoZWNrZWQgb3B0aW9ucyBpbnRvIGRpZmZlcmVudCByb3dzIHRvIHByb2Nlc3MgdGhlbSB0aGF0IHdheS4gCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBkYXRhc2V0IGZvciBGdW5jdGlvbmFsaXRpZXN9CiAgZnVuY3Rpb25hbGl0aWVzX2RpcnR5IDwtIHNlbGVjdChzd3UsIHRpbWVzdGFtcCwgZ2VuZGVyLCBhZ2UsIGxvY2F0aW9uLCBwZXJpb2RpY2l0eSwgYnJhbmQsIGZ1bmN0aW9uYWxpdGllc19kaXJ0eSkKYGBgCgpgYGB7ciBTcGxpdGluZyBGdW5jdGlvbmFsaXRpZXMgaW4gZGlmZmVyZW50IHJvd3N9CiAgZnVuY3Rpb25hbGl0aWVzX3Jvd3MgPC0gc2VwYXJhdGVfbG9uZ2VyX2RlbGltKGZ1bmN0aW9uYWxpdGllc19kaXJ0eSwgZnVuY3Rpb25hbGl0aWVzX2RpcnR5LCAnLCAnKQpgYGAKCmBgYHtyIENoZWNrIGZvciBkaXN0aW5jdCB2YWx1ZXMgaW4gRnVuY3Rpb25hbGl0aWVzIGNvbHVtbn0KdW5pcXVlKGZ1bmN0aW9uYWxpdGllc19yb3dzWydmdW5jdGlvbmFsaXRpZXNfZGlydHknXSkKYGBgCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBjb2x1bW4gd2l0aCBtdXRhdGVkIHZhbHVlcyBpbiBFbmdsaXNoIGZvciBGdW5jdGlvbmFsaXRpZXN9CmZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3MgPC0gbXV0YXRlKGZ1bmN0aW9uYWxpdGllc19yb3dzLCBmdW5jdGlvbmFsaXRpZXMgPSBjYXNlX3doZW4oCiAgZ3JlcGwoJyg/aSlkZXBvcnRlfCg/aSlzcG9ydHwoP2kpcGFzb3MnLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ1Nwb3J0cycsCiAgZ3JlcGwoJyg/aSlwcmVzacOzbiBhcnRlcmlhbHwoP2kpYmxvb2QnLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ0Jsb29kIHByZXNzdXJlJywKICBncmVwbCgnKD9pKWNhbG9yw61hc3woP2kpY2Fsb3JpYXN8KD9pKWNhbG9yaWVzJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdDYWxvcmllcycsCiAgZ3JlcGwoJyg/aSlkaXN0YW5jaWF8KD9pKWRpc3RhbmNlJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdEaXN0YW5jZScsCiAgZ3JlcGwoJyg/aSljYXJkw61hY298KD9pKWhlYXJ0JywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdIZWFydCByYXRlJywKICBncmVwbCgnKD9pKXN1ZcOxb3woP2kpc2xlZXAnLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ1NsZWVwJywKICBncmVwbCgnKD9pKWFndWF8KD9pKXdhdGVyJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdXYXRlcicsCiAgZ3JlcGwoJyg/aSlwZXNvfCg/aSl3ZWlnaHQnLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ1dlaWdodCcsCiAgZ3JlcGwoJyg/aSl0ZW1wZXJhdHVyYXwoP2kpdGVtcGVyYXR1cmUnLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ1RlbXBlcmF0dXJlJywKICBncmVwbCgnKD9pKW1lbnN0cnVhbCcsIGZ1bmN0aW9uYWxpdGllc19kaXJ0eSkgfiAnTWVuc3RydWFsIGhlYWx0aCcsCiAgZ3JlcGwoJyg/aSlhbHRpdHVkfCg/aSlhbHRpdHVkZXxlbGV2YXRpb24nLCBmdW5jdGlvbmFsaXRpZXNfZGlydHkpIH4gJ0FsdGl0dWRlJywKICBncmVwbCgnKD9pKW94aWdlbm98KD9pKW94w61nZW5vJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdPeHlnZW4nLAogIGdyZXBsKCcoP2kpZXN0csOpc3woP2kpc3RyZXNzJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdTdHJlc3MnLAogIGdyZXBsKCcoP2kpbm9pc2V8KD9pKXJ1aWRvJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+ICdOb2lzZScsCiAgZ3JlcGwoJyg/aSlob3JhJywgZnVuY3Rpb25hbGl0aWVzX2RpcnR5KSB+IE5BLAogIAogIFRSVUUgfiBmdW5jdGlvbmFsaXRpZXNfZGlydHkKKSkKdW5pcXVlKGZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3NbJ2Z1bmN0aW9uYWxpdGllcyddKQpgYGAgCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBjb2x1bW4gd2l0aCBtdXRhdGVkIGdyb3VwZWQgdmFsdWVzIGluIEVuZ2xpc2ggZm9yIEZ1bmN0aW9uYWxpdGllc30KZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWRfcm93cyA8LSBtdXRhdGUoZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWRfcm93cywgZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQgPSBjYXNlX3doZW4oCiAgZ3JlcGwoJyg/aSlzcG9ydHwoP2kpZGlzdGFuY2V8KD9pKWFsdGl0dWRlJywgZnVuY3Rpb25hbGl0aWVzKSB+ICdTcG9ydHMnLAogIGdyZXBsKCcoP2kpYmxvb2R8KD9pKWhlYXJ0fCg/aSlzbGVlcHwoP2kpdGVtcGVyYXR1cmV8KD9pKW94eWdlbnwoP2kpbm9pc2UnLCBmdW5jdGlvbmFsaXRpZXMpIH4gJ1JlYWx0aW1lIGhlYWx0aCB0cmFja2VyJywKICBncmVwbCgnKD9pKWNhbG9yaWVzfCg/aSl3YXRlcnwoP2kpd2VpZ2h0fCg/aSltZW5zdHJ1YWwnLCBmdW5jdGlvbmFsaXRpZXMpIH4gJ01hbnVhbCBoZWFsdGggdHJhY2tlcicsCiAgZ3JlcGwoJyg/aSlzdHJlc3N8KD9pKU1pbmRmdWxuZXNzJywgZnVuY3Rpb25hbGl0aWVzKSB+ICdXZWxsYmVpbmcnLAogIAogIFRSVUUgfiBmdW5jdGlvbmFsaXRpZXMKKSkKdW5pcXVlKGZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3NbJ2Z1bmN0aW9uYWxpdGllc19ncm91cGVkJ10pCmBgYCAKIAojIyMgQWN0aXZpdGllcwonYWN0aXZpdGllcycgaXMgYSBxdWVzdGlvbiB0byBkZXRlcm1pbmUgd2hpY2ggYXJlIHRoZSBzcG9ydCBhY3Rpdml0aWVzIG1vc3QgdHJhY2tlZCBmb3IgdGhlIHNtYXJ0d2F0Y2ggdXNlcnMuVGhleSBzaG91bGQgbWFyayBhcyBtYW55IGFjdGl2aXRpZXMgYXMgdGhleSB0cmFjayBvbiB0aGVpciBzbWFydHdhdGNoZXMuIFNvLCB3ZSBuZWVkIHRvIHNwbGl0IGFsbCB0aGlzIGNoZWNrZWQgb3B0aW9ucyBpbnRvIGRpZmZlcmVudCByb3dzIHRvIHByb2Nlc3MgdGhlbSB0aGF0IHdheS4gCgpgYGB7ciBDcmVhdGluZyBhIG5ldyBkYXRhc2V0IGZvciBBY3Rpdml0aWVzfQogIGFjdGl2aXRpZXNfZGlydHkgPC0gc2VsZWN0KHN3dSwgdGltZXN0YW1wLCBnZW5kZXIsIGFnZSwgbG9jYXRpb24sIHBlcmlvZGljaXR5LCBicmFuZCwgYWN0aXZpdGllc19kaXJ0eSkKYGBgCgpgYGB7ciBTcGxpdGluZyBBY3Rpdml0aWVzIGluIGRpZmZlcmVudCByb3dzfQogIGFjdGl2aXRpZXNfcm93cyA8LSBzZXBhcmF0ZV9sb25nZXJfZGVsaW0oYWN0aXZpdGllc19kaXJ0eSwgYWN0aXZpdGllc19kaXJ0eSwgJywgJykKYGBgCgpgYGB7ciBDaGVjayBmb3IgZGlzdGluY3QgdmFsdWVzIGluIEFjdGl2aXRpZXMgY29sdW1ufQp1bmlxdWUoYWN0aXZpdGllc19yb3dzWydhY3Rpdml0aWVzX2RpcnR5J10pCmBgYAoKYGBge3IgQ3JlYXRpbmcgYSBuZXcgY29sdW1uIHdpdGggbXV0YXRlZCB2YWx1ZXMgaW4gRW5nbGlzaCBmb3IgQWN0aXZpdGllc30KYWN0aXZpdGllc19ncm91cGVkX3Jvd3MgPC0gbXV0YXRlKGFjdGl2aXRpZXNfcm93cywgYWN0aXZpdGllcyA9IGNhc2Vfd2hlbigKICBncmVwbCgnKD9pKWNhbWluYXRhfCg/aSlwYXNvc3woP2kpd2Fsa2luZ3woP2kpcGF0aW5hcnwoP2kpc2thdGluZ3woP2kpYmFpbGFyfCg/aSlkYW5jaW5nJywgYWN0aXZpdGllc19kaXJ0eSkgfiAnVXJiYW4gc3BvcnRzJywKICBncmVwbCgnKD9pKWNvcnJlcnwoP2kpcnVubmluZ3woP2kpY2ljbGlzbW98KD9pKWN5Y2xpbmd8KD9pKXRlbmlzfCg/aSl0ZW5uaXN8KD9pKWZ1dGJvbHwoP2kpZm9vdGJhbGx8KD9pKXNvY2NlcnwoP2kpZW5kdXJvJywgYWN0aXZpdGllc19kaXJ0eSkgfiAnUHJvZmVzc2lvbmFsIHNwb3J0cycsCiAgZ3JlcGwoJyg/aSloaWtpbmd8KD9pKXRyYWtraW5nfCg/aSlzZW5kZXJpc21vfCg/aSlzcGxpdGJvYXJkfCg/aSllc3F1aXwoP2kpZXNxdcOtfCg/aSlza2l8KD9pKWVzY2FsYWRhfCg/aSljbGltYmluZycsIGFjdGl2aXRpZXNfZGlydHkpIH4gJ01vdW50YWluIHNwb3J0cycsCiAgZ3JlcGwoJyg/aSluYXRhY2nDs258KD9pKW5hdGFjaW9ufCg/aSlzd2ltbWluZ3woP2kpYnVjZW98KD9pKWRpdmluZycsIGFjdGl2aXRpZXNfZGlydHkpIH4gJ1dhdGVyIHNwb3J0cycsCiAgZ3JlcGwoJyg/aSlnaW1uYXNpb3woP2kpZ3ltfCg/aSllbnRyZW5hbWllbnRvJywgYWN0aXZpdGllc19kaXJ0eSkgfiAnR2VuZXJhbCBneW0gdHJhaW5pbmcnLAogIGdyZXBsKCcoP2kpZnVlcnphfCg/aSljcm9zc2ZpdHwoP2kpZnVuY2lvbmFsfCg/aSljcm9zc3woP2kpc3Ryb25nfCg/aSlmaXRuZXNzfCg/aSl3ZWlnaHR8KD9pKXN0cmVuZ3RofCg/aSl3b3Jrb3V0cycsIGFjdGl2aXRpZXNfZGlydHkpIH4gJ1N0cmVuZ3RoIGFuZCBlbmR1cmFuY2Ugc3BvcnRzJywKICBncmVwbCgnKD9pKXBpbGF0ZXN8KD9pKXlvZ2F8KD9pKXN0cmV0Y2hpbmd8KD9pKW1lZGl0YXRpb24nLCBhY3Rpdml0aWVzX2RpcnR5KSB+ICdSZWxheGluZyBzcG9ydHMnLAoKICBncmVwbCgnKD9pKW5pbmd1bmF8KD9pKWhvcmEnLCBhY3Rpdml0aWVzX2RpcnR5KSB+IE5BLAogIAogIFRSVUUgfiBhY3Rpdml0aWVzX2RpcnR5CikpCnVuaXF1ZShhY3Rpdml0aWVzX2dyb3VwZWRfcm93c1snYWN0aXZpdGllcyddKQpgYGAgIAoKIyBBTkFMSVpFCldlIG5lZWQgdG8gaWRlbnRpZnkgdHJlbmRzIGFuZCByZWxhdGlvbnNoaXBzIHdpdGhpbiBkYXRhIHNvIHdlIGNhbiBhY2N1cmF0ZWx5IGFuc3dlciB0aGUgcXVlc3Rpb24gbWFkZQoKYGBge3IgSW5zdGFsbGluZyBuZWNlc3NhcnkgcGFja2FnZXMgZm9yIGdyYXBoc30KaW5zdGFsbC5wYWNrYWdlcygnZ2dwbG90MicpCmluc3RhbGwucGFja2FnZXMoJ2xlc3NSJykKaW5zdGFsbC5wYWNrYWdlcygnc2NhbGVzJykKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KGxlc3NSKQpsaWJyYXJ5KHNjYWxlcykKYGBgCgojIyBEZW1vZ3JhcGhpYwpXZSB3YW50IHRvIGlkZW50aWZ5IGRlbW9ncmFwaGljIHRyZW5kcyBvbiB0aGUgc2FtcGxlCiogR2VuZGVyCiogQWdlCiogR2VvZ3JhcGhpYyBsb2NhdGlvbgoKIyMjIEdlbmRlcgoKV2UgaWRlbnRpZmllZCB0d28gbWFpbiBnZW5kZXJzIGFuZCBhIHRoaXJkIGZvciB0aG9zZSB3aG8gcmF0ZXIgbm90IHNheS4KCmBgYHtyIEdlbmRlciBkaXN0cmlidXRpb259CmdlbmRlcl90YWJsZSA8LSB0YWJsZShzd3VbJ2dlbmRlciddKQoKUGllQ2hhcnQoZ2VuZGVyX3RhYmxlLCBob2xlID0gMCwgdmFsdWVzID0gIiUiLCBtYWluID0gIkdlbmRlciBkaXN0cmlidXRpb24iLCBmaWxsID0gInJlZHMiKQpgYGAKIyMjIEFnZQoKV2UgY3JlYXRlZCBhZ2UgZ3JvdXBzLCB3aXRoIGEgcmFuZ2Ugb2YgMTAgeWVhcnMgZWFjaC4KCmBgYHtyIEFnZSBkaXN0cmlidXRpb259CmFnZV90YWJsZSA8LSB0YWJsZShzd3VbJ2FnZSddKQoKUGllQ2hhcnQoYWdlX3RhYmxlLCBob2xlID0gMCwgdmFsdWVzID0gIiUiLCBtYWluID0gIkFnZSBkaXN0cmlidXRpb24iLCBmaWxsID0gInJlZHMiKQpgYGAKCiMjIyBHZW9ncmFwaGljIGxvY2F0aW9uCgpXZSB3YW50IHRvIGtub3cgd2hpY2ggaXMgdGhlIGNvbnRpbmVudCBkaXN0cmlidXRpb24gb2Ygc21hcnR3YXRjaGVzIHVzZXJzCgpgYGB7ciBMb2NhdGlvbiAtIE1hcCBkaXN0cmlidXRpb259CiMgVGVsbCBzZiB0byB0cmVhdCB3b3JsZCBtYXAgZGF0YSBhcyBhICdmbGF0JyBzdXJmYWNlIGluc3RlYWQgb2YgYSBzcGhlcmUKc2ZfdXNlX3MyKEZBTFNFKQoKIyBJbXBvcnQgd29ybGQgbWFwLCBkaXNzb2x2ZS91bmlvbiBwb2x5Z29ucyBieSBjb250aW5lbnQsIGFuZCBhZGQgYnViYmxlIGxvbi9sYXQKIyBsb2NhdGlvbnMgZm9yIHBsb3R0aW5nCmNvbnRpbmVudHMgPC0gbmVfY291bnRyaWVzKHJldHVybmNsYXNzPSdzZicpICU+JQogICMgUnVzc2lhIGhhcyBpbmNvcnJlY3QgY29udGluZW50IHZhbHVlLCBzbyBuZWVkIHRvIGNoYW5nZSBpdAogIG11dGF0ZShjb250aW5lbnQgPSBpZmVsc2Uoc292ZXJlaWdudCA9PSAiUnVzc2lhIiwgIkFzaWEiLCBjb250aW5lbnQpKSAlPiUKICBncm91cF9ieShjb250aW5lbnQpICU+JQogIHN1bW1hcmlzZShnZW9tID0gc3RfdW5pb24oZ2VvbWV0cnkpKSAlPiUKICBmaWx0ZXIoIWNvbnRpbmVudCA9PSAiU2V2ZW4gc2VhcyAob3BlbiBvY2VhbikiKSAlPiUKICBtdXRhdGUoY2VudHJvaWRfbG9uID0gc3RfY29vcmRpbmF0ZXMoc3RfY2VudHJvaWQoLikpWywxXSwKICAgICAgICAgY2VudHJvaWRfbGF0ID0gc3RfY29vcmRpbmF0ZXMoc3RfY2VudHJvaWQoLikpWywyXSkKCiMgZGF0YXNldCBjYWxjdWxhdGlvbgpsb2NhdGlvbl9kaXJ0eSA8LSBzZWxlY3Qoc3d1LCBsb2NhdGlvbikKCmxvY2F0aW9uczwtIGxvY2F0aW9uX2RpcnR5ICU+JQogIGdyb3VwX2J5KGxvY2F0aW9uKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKQoKY29sbmFtZXMobG9jYXRpb25zKSA8LSBjKCJjb250aW5lbnQiLCAiY291bnQiKQoKIyBKb2luIGNvdW50IGRhdGEgdG8gY29udGluZW50cwpjb250aW5lbnRzIDwtIGxlZnRfam9pbihjb250aW5lbnRzLCBsb2NhdGlvbnMsIGJ5ID0gImNvbnRpbmVudCIpCgojIFBsb3QKZ2dwbG90KGRhdGEgPSBjb250aW5lbnRzKSArCiAgZ2VvbV9zZigpICsKICBnZW9tX3BvaW50KGFlcyh4ID0gY2VudHJvaWRfbG9uLCB5ID0gY2VudHJvaWRfbGF0LCBzaXplID0gY291bnQsIGNvbG9yID0gInJlZCIpKSArCiAgc2NhbGVfc2l6ZShyYW5nZSA9IGMoMSwgMTApKSArCiAgbGFicyhzaXplID0gIkNvdW50IiwgdGl0bGUgPSAiTG9jYXRpb24gZGlzdHJpYnV0aW9uIikgKwogIHRoZW1lKGF4aXMudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpCgojIEl0IGlzIGEgZ29vZCBoYWJpdCB0byB0dXJuIFMyIGJhY2sgb24gYWZ0ZXIgeW91IGFyZSBkb25lCnNmX3VzZV9zMihUUlVFKQoKYGBgCgojIyMgRGVtb2dyYXBoaWMgcmVsYXRpb25zCgojIyMjIEFnZSB2cyBHZW5kZXIKCmBgYHtyIEFnZSAtIERhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFnZV9wZXJjIDwtIHN3dSAlPiUgCiAgZ3JvdXBfYnkoZ2VuZGVyLCBhZ2UpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50L3N1bShjb3VudCksIHJhdGlvID0gc2NhbGVzOjpwZXJjZW50KHJvdW5kKHBlcmMsIDIpKSkKYGBgCgpgYGB7ciBQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBhZ2UgZ3JvdXBzIHBlciBnZW5kZXJ9CiMgQ2hhcnQKZ2dwbG90KGFnZV9wZXJjLCBhZXMoeCA9IGZhY3RvcihnZW5kZXIpLCB5ID0gcGVyYywgZmlsbCA9IGZhY3RvcihhZ2UpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImFnZSIsIHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBBZ2UgcGVyIEdlbmRlciAoJSknLCBzdWJ0aXRsZSA9ICdTdGFja2VkIGJhcnMgdmVyc2lvbicpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBhZ2VfcGVyYywgYWVzKHkgPSBwZXJjLCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFnZSBncm91cHMiKSkKYGBgCgpgYGB7ciBBZ2UgLSBHcm91cGVkIGJ5IFBlcmMgR2VuZGVyLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gYWdlX3BlcmMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IHBlcmMsIGZpbGwgPSBhZ2UsIGdyb3VwID0gYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAtMC41LCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUGVyY2VudGFnZSIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBBZ2UgcGVyIEdlbmRlciAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgQWdlIC0gR3JvdXBlZCBieSBjb3VudGVkIEdlbmRlciwgd2FybmluZz1UUlVFfQpnZ3Bsb3QoZGF0YSA9IGFnZV9wZXJjKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBjb3VudCwgZmlsbCA9IGFnZSwgZ3JvdXAgPSBhZ2UpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGdlbmRlciwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAtMC41LCBzaXplID0gMwogICkgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEFnZSBwZXIgR2VuZGVyIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKCiMjIyMgQWdlIHZzIExvY2F0aW9uCgpgYGB7ciBBZ2UgLSBMb2NhdGlvbjogRGF0YXNldCBjYWxjdWxhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYWdlX2xvY19wZXJjIDwtIHN3dSAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb24sIGFnZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKQpgYGAKCmBgYHtyIFBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIGFnZSBncm91cHMgcGVyIGxvY2F0aW9ufQojIENoYXJ0CmdncGxvdChhZ2VfbG9jX3BlcmMsIGFlcyh4ID0gZmFjdG9yKGxvY2F0aW9uKSwgeSA9IHBlcmMsIGZpbGwgPSBmYWN0b3IoYWdlKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBwb3NpdGlvbj0iZmlsbCIpICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImFnZSIsIHRpdGxlID0gJ0Rpc3RyaWJ1dGlvbiBvZiBBZ2UgcGVyIExvY2F0aW9uICglKScsIHN1YnRpdGxlID0gJ1N0YWNrZWQgYmFycyB2ZXJzaW9uJykgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBnZW9tX3RleHQoZGF0YSA9IGFnZV9sb2NfcGVyYywgYWVzKHkgPSBwZXJjLCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkFnZSBncm91cHMiKSkKYGBgCgpgYGB7ciBBZ2UgLSBHcm91cGVkIGJ5IFBlcmMgTG9jYXRpb24sIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBhZ2VfbG9jX3BlcmMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgZmlsbCA9IGFnZSwgZ3JvdXAgPSBhZ2UpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGxvY2F0aW9uLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQWdlIHBlciBMb2NhdGlvbiAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgQWdlIC0gR3JvdXBlZCBieSBjb3VudGVkIExvY2F0aW9uLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gYWdlX2xvY19wZXJjKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IGNvdW50LCBmaWxsID0gYWdlLCBncm91cCA9IGFnZSksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gbG9jYXRpb24sIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBBZ2UgcGVyIExvY2F0aW9uIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIyBHZW5kZXIgdnMgTG9jYXRpb24KCmBgYHtyIEdlbmRlciAtIExvY2F0aW9uOiBEYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZW5kZXJfbG9jX3BlcmMgPC0gc3d1ICU+JSAKICBncm91cF9ieShsb2NhdGlvbiwgZ2VuZGVyKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChyb3VuZChwZXJjLCAyKSkpCmBgYAoKYGBge3IgUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgZ2VuZGVyIHBlciBsb2NhdGlvbn0KIyBDaGFydApnZ3Bsb3QoZ2VuZGVyX2xvY19wZXJjLCBhZXMoeCA9IGZhY3Rvcihsb2NhdGlvbiksIHkgPSBwZXJjLCBmaWxsID0gZmFjdG9yKGdlbmRlcikpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb249ImZpbGwiKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJnZW5kZXIiLCB0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgR2VuZGVyIHBlciBMb2NhdGlvbiAoJSknLCBzdWJ0aXRsZSA9ICdTdGFja2VkIGJhcnMgdmVyc2lvbicpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBnZW5kZXJfbG9jX3BlcmMsIGFlcyh5ID0gcGVyYywgbGFiZWwgPSByYXRpbyksIHBvc2l0aW9uID0gcG9zaXRpb25fc3RhY2sodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJHZW5kZXIiKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQpgYGAKCmBgYHtyIEdlbmRlciAtIExvY2F0aW9uOiBHcm91cGVkIGJ5IGNvdW50ZWQgTG9jYXRpb24sIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBnZW5kZXJfbG9jX3BlcmMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gY291bnQsIGZpbGwgPSBnZW5kZXIsIGdyb3VwID0gZ2VuZGVyKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBsb2NhdGlvbiwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IGNvdW50LCBsYWJlbCA9IGNvdW50LCBncm91cCA9IGdlbmRlciksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAsIHNpemUgPSAzCiAgKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiR2VuZGVyIikpICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEdlbmRlciBwZXIgTG9jYXRpb24gKENvdW50KSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgoKIyMgU21hcnR3YXRjaCB1c2FnZSB0cmVuZHMKCldlIHdhbnQgdG8gaWRlbnRpZnkgdHJlbmRzIG9uIHRoZSBzYW1wbGUKKiBQZXJpb2RpY2l0eQoqIEJyYW5kCiogVXNhZ2UKKiBGZWF0dXJlcwoqIEZ1bmN0aW9uYWxpdGllcwoqIEFjdGl2aXRpZXMKCiMjIyBQZXJpb2RpY2l0eQoKV2Ugd2FudCB0byBpZGVudGlmeSBob3cgbWFueSBkYXlzIHRoZSB1c2VycyB1c2VkIHRoZWlyIHNtYXJ0d2F0Y2hlcy4KCmBgYHtyIFBlcmlvZGljaXR5IC0gRGF0YXNldCBjYWxjdWxhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KcGVyaW9kaWNpdHkgPC0gc3d1ICU+JSAKICBncm91cF9ieShwZXJpb2RpY2l0eSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKQpgYGAKCmBgYHtyIFBlcmlvZGljaXR5IHRyZW5kc30Kc3d1ICU+JQogIGdncGxvdChhZXMoeCA9IGZhY3RvcihwZXJpb2RpY2l0eSksIGZpbGwgPSAib3JhbmdlIiwgYWxwaGE9LjYsIHdpZHRoPS40KSkgKwogIGdlb21fYmFyKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGxhYnMoeCA9ICJEYXlzIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gJ0RheXMgb2YgdXNhZ2Ugb2Ygc21hcnR3YXRjaGVzJykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSAuLmNvdW50Li4pLCBzdGF0ID0gImNvdW50Iiwgdmp1c3QgPSAxLjUpCmBgYAoKIyMjIEJyYW5kCgpXZSB3YW50IHRvIGtub3cgd2hpY2ggYXJlIHRoZSBtYWluIGJyYW5kcyBvbiB0aGUgbWFya2V0CgpgYGB7ciBCcmFuZCB0cmVuZHN9IAojIFJlb3JkZXIgZnJvbSBoaWdoZXN0IGZyZXF1ZW5jeSB0byBsb3dlc3QgZnJlcXVlbmN5CnN3dSAlPiUgZHJvcF9uYShicmFuZCkgJT4lIAogIGdncGxvdChhZXMoeCA9IGZjdF9yZXYoZmN0X2luZnJlcShicmFuZCkpLCBmaWxsID0gIm9yYW5nZSIsIGFscGhhPS42LCB3aWR0aD0uNCkpICsKICBnZW9tX2JhcigpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGxhYnMoeCA9ICJCcmFuZCIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICdQb3B1bGFyIGJyYW5kcyBvZiBzbWFydHdhdGNoZXMnKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAtMC4xKQpgYGAKCiMjIyBNYWluIHVzYWdlCgpXZSB3YW50IHRvIGlkZW50aWZ5IHdoaWNoIGlzIHRoZSBtYWluIHVzYWdlIHRoZSB1c2VycyBnaXZlIHRvIHRoZWlyIHNtYXJ0d2F0Y2hlcy4KCmBgYHtyIE1haW4gdXNhZ2UgdHJlbmRzfSAKIyBSZW9yZGVyIGZyb20gaGlnaGVzdCBmcmVxdWVuY3kgdG8gbG93ZXN0IGZyZXF1ZW5jeQpzd3UgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihmY3RfaW5mcmVxKHVzYWdlKSksIGZpbGwgPSAib3JhbmdlIiwgYWxwaGE9LjYsIHdpZHRoPS40KSkgKwogIGdlb21fYmFyKCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJub25lIikrCiAgbGFicyh4ID0gIk1haW4gdXNhZ2UiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAnTWFpbiB1c2FnZSBvZiBzbWFydHdhdGNoZXMnKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAtMC4xKQpgYGAKCiMjIyBGZWF0dXJlcwoKV2Ugd2FudCB0byBpZGVudGlmeSB3aGljaCBhcmUgdGhlIGRldGFpbGVkIHNtYXJ0d2F0Y2ggZmVhdHVyZXMgdGhlIHVzZXJzIHVzZSB0aGUgbW9zdC4KCmBgYHtyIEZlYXR1cmVzIHRyZW5kc30gCiMgUmVvcmRlciBmcm9tIGhpZ2hlc3QgZnJlcXVlbmN5IHRvIGxvd2VzdCBmcmVxdWVuY3kKZmVhdHVyZXNfcm93cyAlPiUKICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmV2KGZjdF9pbmZyZXEoZmVhdHVyZXMpKSwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYT0uNiwgd2lkdGg9LjQpKSArCiAgZ2VvbV9iYXIoKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsKICBsYWJzKHggPSAiRmVhdHVyZXMiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAnUG9wdWxhciBmZWF0dXJlcyBvZiBzbWFydHdhdGNoZXMnKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAtMC4xKQpgYGAKCldlIGNyZWF0ZSBsYXJnZXIgY2F0ZWdvcmllcyBmcm9tIGZlYXR1cmVzIHRvIGdldCBhIGJpZ2dlciBwaWN0dXJlIG9mIHRoZSB0cmVuZHMKCmBgYHtyIEZlYXR1cmVzIGdyb3VwZWQgdHJlbmRzfSAKIyBSZW9yZGVyIGZyb20gaGlnaGVzdCBmcmVxdWVuY3kgdG8gbG93ZXN0IGZyZXF1ZW5jeQpmZWF0dXJlc19ncm91cGVkX3Jvd3MgJT4lCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihmY3RfaW5mcmVxKGZlYXR1cmVzX2dyb3VwZWQpKSwgZmlsbCA9ICJvcmFuZ2UiLCBhbHBoYT0uNiwgd2lkdGg9LjQpKSArCiAgZ2VvbV9iYXIoKSArCiAgY29vcmRfZmxpcCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb249Im5vbmUiKSsKICBsYWJzKHggPSAiRmVhdHVyZXMiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAnUG9wdWxhciBncm91cGVkIGZlYXR1cmVzIG9mIHNtYXJ0d2F0Y2hlcycpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgc3RhdCA9ICJjb3VudCIsIHZqdXN0ID0gMC41LCBoanVzdCA9IC0wLjEpCmBgYAoKIyMjIEZ1bmN0aW9uYWxpdGllcwoKV2Ugd2FudCB0byBpZGVudGlmeSB3aGljaCBhcmUgdGhlIG1vc3QgdXNlZCBmdW5jdGlvbmFsaXRpZXMgdGhhdCBhcmUgdHJhY2tlZCBmb3IgdGhlIHVzZXJzIGluIHRoZWlyIHNtYXJ0d2F0Y2guCgpgYGB7ciBUcmFja2VkIGZ1bmN0aW9uYWxpdGllcyB0cmVuZHN9IAojIFJlb3JkZXIgZnJvbSBoaWdoZXN0IGZyZXF1ZW5jeSB0byBsb3dlc3QgZnJlcXVlbmN5CmZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3MgJT4lIGRyb3BfbmEoZnVuY3Rpb25hbGl0aWVzKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gZmN0X3JldihmY3RfaW5mcmVxKGZ1bmN0aW9uYWxpdGllcykpLCBmaWxsID0gIm9yYW5nZSIsIGFscGhhPS42LCB3aWR0aD0uNCkpICsKICBnZW9tX2JhcigpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGxhYnMoeCA9ICJUcmFja2VkIGZ1bmN0aW9uYWxpdGllcyIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICdQb3B1bGFyIHRyYWNrZWQgZnVuY3Rpb25hbGl0aWVzIG9mIHNtYXJ0d2F0Y2hlcycpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsID0gLi5jb3VudC4uKSwgc3RhdCA9ICJjb3VudCIsIHZqdXN0ID0gMC41LCBoanVzdCA9IC0wLjEpCmBgYAoKV2UgY3JlYXRlIGxhcmdlciBjYXRlZ29yaWVzIGZyb20gZnVuY3Rpb25hbGl0aWVzIHRvIGdldCBhIGJpZ2dlciBwaWN0dXJlIG9mIHRoZSB0cmVuZHMKCmBgYHtyIEZ1bmN0aW9uYWxpdGllcyBncm91cGVkIHRyZW5kc30gCiMgUmVvcmRlciBmcm9tIGhpZ2hlc3QgZnJlcXVlbmN5IHRvIGxvd2VzdCBmcmVxdWVuY3kKZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWRfcm93cyAlPiUgZHJvcF9uYShmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkgJT4lIAogIGdncGxvdChhZXMoeCA9IGZjdF9yZXYoZmN0X2luZnJlcShmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkpLCBmaWxsID0gIm9yYW5nZSIsIGFscGhhPS42LCB3aWR0aD0uNCkpICsKICBnZW9tX2JhcigpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGxhYnMoeCA9ICJGdW5jdGlvbmFsaXRpZXMiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAnUG9wdWxhciBncm91cGVkIGZ1bmN0aW9uYWxpdGllcyBvZiBzbWFydHdhdGNoZXMnKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IC4uY291bnQuLiksIHN0YXQgPSAiY291bnQiLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxLjEpCmBgYAoKCiMjIyBVc2VyIGFjdGl2aXRpZXMKCldlIHdhbnQgdG8ga25vdyB3aGljaCBhcmUgdGhlIHNwb3J0IGFjdGl2aXRpZXMgbW9zdCB0cmFja2VkIGZvciB0aGUgdXNlcnMgaW4gdGhlaXIgc21hcnR3YXRjaC4KCmBgYHtyIFVzZXIgYWN0aXZpdGllcyB0cmVuZHN9IAojIFJlb3JkZXIgZnJvbSBoaWdoZXN0IGZyZXF1ZW5jeSB0byBsb3dlc3QgZnJlcXVlbmN5CmFjdGl2aXRpZXNfZ3JvdXBlZF9yb3dzICU+JSBkcm9wX25hKGFjdGl2aXRpZXMpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBmY3RfcmV2KGZjdF9pbmZyZXEoYWN0aXZpdGllcykpLCBmaWxsID0gIm9yYW5nZSIsIGFscGhhPS42LCB3aWR0aD0uNCkpICsKICBnZW9tX2JhcigpICsKICBjb29yZF9mbGlwKCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbj0ibm9uZSIpKwogIGxhYnMoeCA9ICJTcG9ydCBhY3Rpdml0aWVzIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gJ1BvcHVsYXIgc3BvcnQgYWN0aXZpdGllcyB0cmFja2VkIGJ5IHVzZXJzJykgKwogIGdlb21fdGV4dChhZXMobGFiZWwgPSAuLmNvdW50Li4pLCBzdGF0ID0gImNvdW50Iiwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMS4xKQpgYGAKCiMjIEVzdGFibGlzaGluZyByZWxhdGlvbnMgYmV0d2VlbiB2YXJpYWJsZXMKCiMjIyBQZXJpb2RpY2l0eQoKIyMjIyBQZXJpb2RpY2l0eSB2cyBHZW5kZXIKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgcGVyaW9kaWNpdHkgb2YgYSBzbWFydHdhdGNoIGFuZCB0aGUgdXNlcidzIGdlbmRlcgoKYGBge3IgUGVyaW9kaWNpdHkgLSBHZW5kZXI6IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBlcmlvZGljaXR5X2dlbmRlciA8LSBzd3UgJT4lIAogIGdyb3VwX2J5KGdlbmRlciwgcGVyaW9kaWNpdHkpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50L3N1bShjb3VudCksIHJhdGlvID0gc2NhbGVzOjpwZXJjZW50KHJvdW5kKHBlcmMsIDIpKSkgJT4lIAogIGRyb3BfbmEocGVyaW9kaWNpdHkpCmBgYAoKYGBge3IgUGVyaW9kaWNpdHkgLSBHZW5kZXI6IFBlcmNlbnRhZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QocGVyaW9kaWNpdHlfZ2VuZGVyLCBhZXMoeCA9IGZhY3RvcihnZW5kZXIpLCB5ID0gcGVyYyoxMDAsIGZpbGwgPSBmYWN0b3IocGVyaW9kaWNpdHkpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gInBlcmlvZGljaXR5IiwgdGl0bGUgPSAiUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIEdlbmRlciIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBwZXJpb2RpY2l0eV9nZW5kZXIsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZT0iUGVyaW9kaWNpdHkiKSkKYGBgCgpgYGB7ciBQZXJpb2RpY2l0eSAtIEdlbmRlcjogR3JvdXBlZCBieSBQZXJjIEdlbmRlciwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChkYXRhID0gcGVyaW9kaWNpdHlfZ2VuZGVyKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBwZXJjLCBmaWxsID0gcGVyaW9kaWNpdHksIGdyb3VwID0gcGVyaW9kaWNpdHkpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGdlbmRlciwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBwZXJjLCBsYWJlbCA9IHJhdGlvLCBncm91cCA9IHBlcmlvZGljaXR5KSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gLTAuNSwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIEdlbmRlciAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgUGVyaW9kaWNpdHkgLSBHZW5kZXI6IEdyb3VwZWQgYnkgY291bnRlZCBHZW5kZXIsIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBwZXJpb2RpY2l0eV9nZW5kZXIpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IGNvdW50LCBmaWxsID0gcGVyaW9kaWNpdHksIGdyb3VwID0gcGVyaW9kaWNpdHkpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGdlbmRlciwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBwZXJpb2RpY2l0eSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IC0wLjUsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIEdlbmRlciAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgUGVyaW9kaWNpdHkgdnMgQWdlCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHBlcmlvZGljaXR5IG9mIGEgc21hcnR3YXRjaCBhbmQgdGhlIHVzZXIncyBhZ2UKCmBgYHtyIFBlcmlvZGljaXR5IC0gQWdlOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwZXJpb2RpY2l0eV9hZ2UgPC0gc3d1ICU+JSAKICBncm91cF9ieShhZ2UsIHBlcmlvZGljaXR5KSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChyb3VuZChwZXJjLCAyKSkpICU+JSAKICBkcm9wX25hKHBlcmlvZGljaXR5KQpgYGAKCmBgYHtyIFBlcmlvZGljaXR5IC0gQWdlOiBQZXJjZW50YWdlLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KHBlcmlvZGljaXR5X2FnZSwgYWVzKHggPSBmYWN0b3IoYWdlKSwgeSA9IHBlcmMqMTAwLCBmaWxsID0gZmFjdG9yKHBlcmlvZGljaXR5KSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBwb3NpdGlvbj0iZmlsbCIpICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJwZXJpb2RpY2l0eSIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIFBlcmlvZGljaXR5IHBlciBBZ2UiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gcGVyaW9kaWNpdHlfYWdlLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGU9IlBlcmlvZGljaXR5IikpCmBgYAoKYGBge3IgUGVyaW9kaWNpdHkgLSBBZ2U6IEdyb3VwZWQgYnkgUGVyYyBBZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IHBlcmlvZGljaXR5X2FnZSkgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgZmlsbCA9IHBlcmlvZGljaXR5LCBncm91cCA9IHBlcmlvZGljaXR5KSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBwZXJpb2RpY2l0eSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IC0wLjUsIHNpemUgPSAzCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFBlcmlvZGljaXR5IHBlciBBZ2UgKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIFBlcmlvZGljaXR5IC0gQWdlOiBHcm91cGVkIGJ5IGNvdW50ZWQgQWdlLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gcGVyaW9kaWNpdHlfYWdlKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBhZ2UsIHkgPSBjb3VudCwgZmlsbCA9IHBlcmlvZGljaXR5LCBncm91cCA9IHBlcmlvZGljaXR5KSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gY291bnQsIGxhYmVsID0gY291bnQsIGdyb3VwID0gcGVyaW9kaWNpdHkpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIEFnZSAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgUGVyaW9kaWNpdHkgdnMgTG9jYXRpb24KCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgcGVyaW9kaWNpdHkgb2YgYSBzbWFydHdhdGNoIGFuZCB0aGUgdXNlcidzIGxvY2F0aW9uCgpgYGB7ciBQZXJpb2RpY2l0eSAtIExvY2F0aW9uOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwZXJpb2RpY2l0eV9sb2NhdGlvbiA8LSBzd3UgJT4lIAogIGdyb3VwX2J5KGxvY2F0aW9uLCBwZXJpb2RpY2l0eSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUgCiAgZHJvcF9uYShwZXJpb2RpY2l0eSkKYGBgCgpgYGB7ciBQZXJpb2RpY2l0eSAtIExvY2F0aW9uOiBQZXJjZW50YWdlLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KHBlcmlvZGljaXR5X2xvY2F0aW9uLCBhZXMoeCA9IGZhY3Rvcihsb2NhdGlvbiksIHkgPSBwZXJjKjEwMCwgZmlsbCA9IGZhY3RvcihwZXJpb2RpY2l0eSkpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb249ImZpbGwiKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJwZXJpb2RpY2l0eSIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIFBlcmlvZGljaXR5IHBlciBMb2NhdGlvbiIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBwZXJpb2RpY2l0eV9sb2NhdGlvbiwgYWVzKHkgPSBjb3VudCwgbGFiZWwgPSByYXRpbyksIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlPSJQZXJpb2RpY2l0eSIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpCmBgYAoKYGBge3IgUGVyaW9kaWNpdHkgLSBMb2NhdGlvbjogR3JvdXBlZCBieSBQZXJjIExvY2F0aW9uLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KGRhdGEgPSBwZXJpb2RpY2l0eV9sb2NhdGlvbikgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBwZXJjLCBmaWxsID0gcGVyaW9kaWNpdHksIGdyb3VwID0gcGVyaW9kaWNpdHkpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGxvY2F0aW9uLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBwZXJpb2RpY2l0eSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAsIHNpemUgPSAzCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIExvY2F0aW9uICglKSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7ciBQZXJpb2RpY2l0eSAtIExvY2F0aW9uOiBHcm91cGVkIGJ5IGNvdW50ZWQgTG9jYXRpb24sIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBwZXJpb2RpY2l0eV9sb2NhdGlvbikgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBjb3VudCwgZmlsbCA9IHBlcmlvZGljaXR5LCBncm91cCA9IHBlcmlvZGljaXR5KSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBsb2NhdGlvbiwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IGNvdW50LCBsYWJlbCA9IGNvdW50LCBncm91cCA9IHBlcmlvZGljaXR5KSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMC4xLCBzaXplID0gMwogICkgKwogIGxhYnMoeCA9ICJMb2NhdGlvbiIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgUGVyaW9kaWNpdHkgcGVyIExvY2F0aW9uIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKCiMjIyMgQnJhbmQgdnMgR2VuZGVyCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIGJyYW5kIG9mIGEgc21hcnR3YXRjaCBhbmQgdGhlIHVzZXIncyBnZW5kZXIKCmBgYHtyIEJyYW5kIC0gR2VuZGVyOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpicmFuZF9nZW5kZXIgPC0gc3d1ICU+JSAKICBncm91cF9ieShnZW5kZXIsIGJyYW5kKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChyb3VuZChwZXJjLCAyKSkpICU+JSAKICBkcm9wX25hKGJyYW5kKQpgYGAKCmBgYHtyIEJyYW5kIC0gR2VuZGVyOiBQZXJjZW50YWdlLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KGJyYW5kX2dlbmRlciwgYWVzKHggPSBmYWN0b3IoZ2VuZGVyKSwgeSA9IHBlcmMgKiAxMDAsIGZpbGwgPSBmYWN0b3IoYnJhbmQpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImJyYW5kIiwgdGl0bGUgPSAiUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgQnJhbmQgcGVyIEdlbmRlciIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBicmFuZF9nZW5kZXIsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJCcmFuZCIpKQpgYGAKCmBgYHtyIEJyYW5kIC0gR2VuZGVyOiBHcm91cGVkIGJ5IFBlcmMgR2VuZGVyLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KGRhdGEgPSBicmFuZF9nZW5kZXIpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IHBlcmMsIGZpbGwgPSBicmFuZCwgZ3JvdXAgPSBicmFuZCksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gZ2VuZGVyLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IHBlcmMsIGxhYmVsID0gcmF0aW8sIGdyb3VwID0gYnJhbmQpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUGVyY2VudGFnZSIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCcmFuZCBwZXIgZ2VuZGVyICglKSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgpgYGB7ciBCcmFuZCAtIEdlbmRlcjogR3JvdXBlZCBieSBjb3VudGVkIEdlbmRlciwgd2FybmluZz1UUlVFfQpnZ3Bsb3QoZGF0YSA9IGJyYW5kX2dlbmRlcikgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gY291bnQsIGZpbGwgPSBicmFuZCwgZ3JvdXAgPSBicmFuZCksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gZ2VuZGVyLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IGNvdW50LCBsYWJlbCA9IGNvdW50LCBncm91cCA9IGJyYW5kKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMC4xLCBzaXplID0gMwogICkgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJyYW5kIHBlciBHZW5kZXIgKENvdW50KSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgojIyMjIEJyYW5kIHZzIEFnZQoKV2Ugd2FudCB0byBpZGVudGlmeSBpZiB0aGVyZSBhcmUgYSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBicmFuZCBvZiBhIHNtYXJ0d2F0Y2ggYW5kIHRoZSB1c2VyJ3MgYWdlCgpgYGB7ciBCcmFuZCAtIEFnZTogZGF0YXNldCBjYWxjdWxhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KYnJhbmRfYWdlIDwtIHN3dSAlPiUgCiAgZ3JvdXBfYnkoYWdlLCBicmFuZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUgCiAgZHJvcF9uYShicmFuZCkKYGBgCgpgYGB7ciBCcmFuZCAtIEFnZTogUGVyY2VudGFnZSwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChicmFuZF9hZ2UsIGFlcyh4ID0gZmFjdG9yKGFnZSksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKGJyYW5kKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBwb3NpdGlvbj0iZmlsbCIpICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJicmFuZCIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIEJyYW5kIHBlciBBZ2UiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gYnJhbmRfYWdlLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiQnJhbmQiKSkKYGBgCgpgYGB7ciBCcmFuZCAtIEFnZTogR3JvdXBlZCBieSBQZXJjIEFnZSwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChkYXRhID0gYnJhbmRfYWdlKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBhZ2UsIHkgPSBwZXJjLCBmaWxsID0gYnJhbmQsIGdyb3VwID0gYnJhbmQpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGFnZSwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBhZ2UsIHkgPSBwZXJjLCBsYWJlbCA9IHJhdGlvLCBncm91cCA9IGJyYW5kKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMCwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgQnJhbmQgcGVyIEFnZSAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgQnJhbmQgLSBBZ2U6IEdyb3VwZWQgYnkgY291bnRlZCBBZ2UsIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBicmFuZF9hZ2UpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGFnZSwgeSA9IGNvdW50LCBmaWxsID0gYnJhbmQsIGdyb3VwID0gYnJhbmQpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGFnZSwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBhZ2UsIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBicmFuZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBCcmFuZCBwZXIgQWdlIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIyBCcmFuZCB2cyBMb2NhdGlvbgoKV2Ugd2FudCB0byBpZGVudGlmeSBpZiB0aGVyZSBhcmUgYSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBicmFuZCBvZiBhIHNtYXJ0d2F0Y2ggYW5kIHRoZSB1c2VyJ3MgbG9jYXRpb24KCmBgYHtyIEJyYW5kIC0gTG9jYXRpb246IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmJyYW5kX2xvY2F0aW9uIDwtIHN3dSAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb24sIGJyYW5kKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChyb3VuZChwZXJjLCAyKSkpICU+JSAKICBkcm9wX25hKGJyYW5kKQpgYGAKCmBgYHtyIEJyYW5kIC0gTG9jYXRpb246IFBlcmNlbnRhZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoYnJhbmRfbG9jYXRpb24sIGFlcyh4ID0gZmFjdG9yKGxvY2F0aW9uKSwgeSA9IHBlcmMgKiAxMDAsIGZpbGwgPSBmYWN0b3IoYnJhbmQpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJMb2NhdGlvbiIsIHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiYnJhbmQiLCB0aXRsZSA9ICJQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBCcmFuZCBwZXIgTG9jYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gYnJhbmRfbG9jYXRpb24sIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJCcmFuZCIpKQpgYGAKCmBgYHtyIEJyYW5kIC0gTG9jYXRpb246IEdyb3VwZWQgYnkgUGVyYyBMb2NhdGlvbiwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChkYXRhID0gYnJhbmRfbG9jYXRpb24pICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgZmlsbCA9IGJyYW5kLCBncm91cCA9IGJyYW5kKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBsb2NhdGlvbiwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IHBlcmMsIGxhYmVsID0gcmF0aW8sIGdyb3VwID0gYnJhbmQpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJyYW5kIHBlciBMb2NhdGlvbiAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgQnJhbmQgLSBMb2NhdGlvbjogR3JvdXBlZCBieSBjb3VudGVkIExvY2F0aW9uLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gYnJhbmRfbG9jYXRpb24pICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gY291bnQsIGZpbGwgPSBicmFuZCwgZ3JvdXAgPSBicmFuZCksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gbG9jYXRpb24sIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBicmFuZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEJyYW5kIHBlciBMb2NhdGlvbiAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyBVc2FnZQoKIyMjIyBVc2FnZSB2cyBHZW5kZXIKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgdXNhZ2Ugb2YgYSBzbWFydHdhdGNoIGFuZCB0aGUgdXNlcidzIGdlbmRlcgoKYGBge3IgVXNhZ2UgLSBHZW5kZXI6IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdlbmRlcl91c2FnZSA8LSBzd3UgJT4lIAogIGdyb3VwX2J5KGdlbmRlciwgdXNhZ2UpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50L3N1bShjb3VudCksIHJhdGlvID0gc2NhbGVzOjpwZXJjZW50KHJvdW5kKHBlcmMsIDIpKSkgJT4lCiAgZHJvcF9uYSh1c2FnZSkKYGBgCgpgYGB7ciBVc2FnZSAtIEdlbmRlcjogUGVyY2VudGFnZSwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChnZW5kZXJfdXNhZ2UsIGFlcyh4ID0gZmFjdG9yKGdlbmRlciksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKHVzYWdlKSkpICsKICBnZW9tX2JhcihzdGF0ID0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb24gPSAiZmlsbCIpICsKICBsYWJzKHggPSAiR2VuZGVyIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJ1c2FnZSIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIFVzYWdlIHBlciBHZW5kZXIiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gZ2VuZGVyX3VzYWdlLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGU9IlVzYWdlIikpCmBgYAoKYGBge3IgVXNhZ2UgLSBHZW5kZXI6IEdyb3VwZWQgYnkgUGVyYyBHZW5kZXIsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGdlbmRlcl91c2FnZSkgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gcGVyYywgZmlsbCA9IHVzYWdlLCBncm91cCA9IHVzYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSB1c2FnZSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAsIHNpemUgPSAzCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBsYWJzKHggPSAiR2VuZGVyIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFVzYWdlIHBlciBHZW5kZXIgKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIFVzYWdlIC0gR2VuZGVyOiBHcm91cGVkIGJ5IGNvdW50ZWQgR2VuZGVyLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gZ2VuZGVyX3VzYWdlKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBjb3VudCwgZmlsbCA9IHVzYWdlLCBncm91cCA9IHVzYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gY291bnQsIGxhYmVsID0gY291bnQsIGdyb3VwID0gdXNhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgVXNhZ2UgcGVyIEdlbmRlciAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgVXNhZ2UgdnMgQWdlCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHVzYWdlIG9mIGEgc21hcnR3YXRjaCBhbmQgdGhlIHVzZXIncyBhZ2UKCmBgYHtyIFVzYWdlIC0gQWdlOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphZ2VfdXNhZ2UgPC0gc3d1ICU+JSAKICBncm91cF9ieShhZ2UsIHVzYWdlKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChyb3VuZChwZXJjLCAyKSkpICU+JQogIGRyb3BfbmEodXNhZ2UpCmBgYAoKYGBge3IgVXNhZ2UgLSBBZ2U6IFBlcmNlbnRhZ2V9CiMgQ2hhcnQKZ2dwbG90KGFnZV91c2FnZSwgYWVzKHggPSBmYWN0b3IoYWdlKSwgeSA9IHBlcmMgKiAxMDAsIGZpbGwgPSBmYWN0b3IodXNhZ2UpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gInVzYWdlIiwgdGl0bGUgPSAiUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgVXNhZ2UgcGVyIEFnZSIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBhZ2VfdXNhZ2UsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJVc2FnZSIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpCmBgYAoKYGBge3IgVXNhZ2UgLSBBZ2U6IEdyb3VwZWQgYnkgUGVyYyBBZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGFnZV91c2FnZSkgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgZmlsbCA9IHVzYWdlLCBncm91cCA9IHVzYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSB1c2FnZSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAsIHNpemUgPSAzCiAgKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFVzYWdlIHBlciBBZ2UgKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIFVzYWdlIC0gQWdlOiBHcm91cGVkIGJ5IGNvdW50ZWQgQWdlLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gYWdlX3VzYWdlKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBhZ2UsIHkgPSBjb3VudCwgZmlsbCA9IHVzYWdlLCBncm91cCA9IHVzYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gY291bnQsIGxhYmVsID0gY291bnQsIGdyb3VwID0gdXNhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiQ291bnQiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgVXNhZ2UgcGVyIEFnZSAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgVXNhZ2UgdnMgTG9jYXRpb24KCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgdXNhZ2Ugb2YgYSBzbWFydHdhdGNoIGFuZCB0aGUgdXNlcidzIGxvY2F0aW9uCgpgYGB7ciBVc2FnZSAtIExvY2F0aW9uOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpsb2NhdGlvbl91c2FnZSA8LSBzd3UgJT4lIAogIGdyb3VwX2J5KGxvY2F0aW9uLCB1c2FnZSkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUKICBkcm9wX25hKHVzYWdlKQpgYGAKCmBgYHtyIFVzYWdlIC0gTG9jYXRpb246IFBlcmNlbnRhZ2V9CiMgQ2hhcnQKZ2dwbG90KGxvY2F0aW9uX3VzYWdlLCBhZXMoeCA9IGZhY3Rvcihsb2NhdGlvbiksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKHVzYWdlKSkpICsKICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnMoeCA9ICJMb2NhdGlvbiIsIHkgPSAiUGVyY2VudCIsIGZpbGwgPSAidXNhZ2UiLCB0aXRsZSA9ICJQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBVc2FnZSBwZXIgTG9jYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gbG9jYXRpb25fdXNhZ2UsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbD1ndWlkZV9sZWdlbmQodGl0bGUgPSAiVXNhZ2UiKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQpgYGAKCmBgYHtyIFVzYWdlIC0gTG9jYXRpb246IEdyb3VwZWQgYnkgUGVyYyBMb2NhdGlvbiwgd2FybmluZz1UUlVFfQojIENoYXJ0CmdncGxvdChkYXRhID0gbG9jYXRpb25fdXNhZ2UpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgZmlsbCA9IHVzYWdlLCBncm91cCA9IHVzYWdlKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBsb2NhdGlvbiwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IHBlcmMsIGxhYmVsID0gcmF0aW8sIGdyb3VwID0gdXNhZ2UpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFVzYWdlIHBlciBMb2NhdGlvbiAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgVXNhZ2UgLSBMb2NhdGlvbjogR3JvdXBlZCBieSBjb3VudGVkIExvY2F0aW9uLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gbG9jYXRpb25fdXNhZ2UpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gY291bnQsIGZpbGwgPSB1c2FnZSwgZ3JvdXAgPSB1c2FnZSksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gbG9jYXRpb24sIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSB1c2FnZSksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIFVzYWdlIHBlciBMb2NhdGlvbiAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyBGZWF0dXJlcwoKIyMjIyBGZWF0dXJlcyB2cyBHZW5kZXIKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgdXNlZCBmZWF0dXJlcyBvZiBhIHNtYXJ0d2F0Y2ggYW5kIHRoZSB1c2VyJ3MgZ2VuZGVyLgoKYGBge3IgRmVhdHVyZXMgLSBHZW5kZXI6IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdlbmRlcl9mZWF0dXJlcyA8LSBmZWF0dXJlc19ncm91cGVkX3Jvd3MgJT4lIAogIGdyb3VwX2J5KGdlbmRlciwgZmVhdHVyZXNfZ3JvdXBlZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUKICBkcm9wX25hKGZlYXR1cmVzX2dyb3VwZWQpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBHZW5kZXI6IFBlcmNlbnRhZ2V9CiMgQ2hhcnQKZ2dwbG90KGdlbmRlcl9mZWF0dXJlcywgYWVzKHggPSBmYWN0b3IoZ2VuZGVyKSwgeSA9IHBlcmMgKiAxMDAsIGZpbGwgPSBmYWN0b3IoZmVhdHVyZXNfZ3JvdXBlZCkpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gMC43LCBwb3NpdGlvbiA9ICJmaWxsIikgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImZlYXR1cmVzX2dyb3VwZWQiLCB0aXRsZSA9ICJQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgR2VuZGVyIikgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBnZW9tX3RleHQoZGF0YSA9IGdlbmRlcl9mZWF0dXJlcywgYWVzKHkgPSBjb3VudCwgbGFiZWwgPSByYXRpbyksIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGd1aWRlcyhmaWxsID0gZ3VpZGVfbGVnZW5kKHRpdGxlID0gIkZlYXR1cmVzIikpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBHZW5kZXI6IEdyb3VwZWQgYnkgUGVyYyBHZW5kZXIsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGdlbmRlcl9mZWF0dXJlcykgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gcGVyYywgZmlsbCA9IGZlYXR1cmVzX2dyb3VwZWQsIGdyb3VwID0gZmVhdHVyZXNfZ3JvdXBlZCksIAogICAgc3RhdCA9ICdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMCwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRmVhdHVyZXMgcGVyIEdlbmRlciAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBHZW5kZXI6IEdyb3VwZWQgYnkgY291bnRlZCBHZW5kZXIsIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBnZW5kZXJfZmVhdHVyZXMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IGNvdW50LCBmaWxsID0gZmVhdHVyZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBnZW5kZXIsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gY291bnQsIGxhYmVsID0gY291bnQsIGdyb3VwID0gZmVhdHVyZXNfZ3JvdXBlZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiR2VuZGVyIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgR2VuZGVyIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIyBGZWF0dXJlcyB2cyBBZ2UKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgdXNlZCBmZWF0dXJlcyBvZiBhIHNtYXJ0d2F0Y2ggYW5kIHRoZSB1c2VyJ3MgYWdlLgoKYGBge3IgRmVhdHVyZXMgLSBBZ2U6IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmFnZV9mZWF0dXJlcyA8LSBmZWF0dXJlc19ncm91cGVkX3Jvd3MgJT4lIAogIGdyb3VwX2J5KGFnZSwgZmVhdHVyZXNfZ3JvdXBlZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUgCiAgZHJvcF9uYShmZWF0dXJlc19ncm91cGVkKQpgYGAKCmBgYHtyIEZlYXR1cmVzIC0gQWdlOiBQZXJjZW50YWdlfQojIENoYXJ0CmdncGxvdChhZ2VfZmVhdHVyZXMsIGFlcyh4ID0gZmFjdG9yKGFnZSksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKGZlYXR1cmVzX2dyb3VwZWQpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb24gPSAiZmlsbCIpICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJmZWF0dXJlc19ncm91cGVkIiwgdGl0bGUgPSAiUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgRmVhdHVyZXMgcGVyIEFnZSIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBhZ2VfZmVhdHVyZXMsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJGZWF0dXJlcyIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBBZ2U6IEdyb3VwZWQgYnkgUGVyYyBBZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGFnZV9mZWF0dXJlcykgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgZmlsbCA9IGZlYXR1cmVzX2dyb3VwZWQsIGdyb3VwID0gZmVhdHVyZXNfZ3JvdXBlZCksIAogICAgc3RhdCA9ICdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMCwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRmVhdHVyZXMgcGVyIEFnZSAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBBZ2U6IEdyb3VwZWQgYnkgY291bnRlZCBBZ2UsIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBhZ2VfZmVhdHVyZXMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGFnZSwgeSA9IGNvdW50LCBmaWxsID0gZmVhdHVyZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gY291bnQsIGxhYmVsID0gY291bnQsIGdyb3VwID0gZmVhdHVyZXNfZ3JvdXBlZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgQWdlIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIyBGZWF0dXJlcyB2cyBMb2NhdGlvbgoKV2Ugd2FudCB0byBpZGVudGlmeSBpZiB0aGVyZSBhcmUgYSByZWxhdGlvbiBiZXR3ZWVuIHRoZSBmZWF0dXJlcyBvZiBhIHNtYXJ0d2F0Y2ggYW5kIHRoZSB1c2VyJ3MgbG9jYXRpb24KCmBgYHtyIEZlYXR1cmVzIC0gTG9jYXRpb246IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxvY2F0aW9uX2ZlYXR1cmVzIDwtIGZlYXR1cmVzX2dyb3VwZWRfcm93cyAlPiUgCiAgZ3JvdXBfYnkobG9jYXRpb24sIGZlYXR1cmVzX2dyb3VwZWQpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50L3N1bShjb3VudCksIHJhdGlvID0gc2NhbGVzOjpwZXJjZW50KHJvdW5kKHBlcmMsIDIpKSkgJT4lCiAgZHJvcF9uYShmZWF0dXJlc19ncm91cGVkKQpgYGAKCmBgYHtyIEZlYXR1cmVzIC0gTG9jYXRpb246IFBlcmNlbnRhZ2V9CiMgQ2hhcnQKZ2dwbG90KGxvY2F0aW9uX2ZlYXR1cmVzLCBhZXMoeCA9IGZhY3Rvcihsb2NhdGlvbiksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKGZlYXR1cmVzX2dyb3VwZWQpKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb24gPSAiZmlsbCIpICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImZlYXR1cmVzX2dyb3VwZWQiLCB0aXRsZSA9ICJQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgTG9jYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gbG9jYXRpb25fZmVhdHVyZXMsIGFlcyh5ID0gY291bnQsIGxhYmVsID0gcmF0aW8pLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2ZpbGwodmp1c3QgPSAwLjUpKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IHNjYWxlczo6cGVyY2VudF9mb3JtYXQoYWNjdXJhY3kgPSA1TCkpICsKICBndWlkZXMoZmlsbCA9IGd1aWRlX2xlZ2VuZCh0aXRsZSA9ICJGZWF0dXJlcyIpKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSkpCmBgYAoKYGBge3IgRmVhdHVyZXMgLSBMb2NhdGlvbjogR3JvdXBlZCBieSBQZXJjIExvY2F0aW9uLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KGRhdGEgPSBsb2NhdGlvbl9mZWF0dXJlcykgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBwZXJjLCBmaWxsID0gZmVhdHVyZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwgCiAgICBzdGF0ID0gJ2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGxvY2F0aW9uLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMCwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJMb2NhdGlvbiIsIHkgPSAiUGVyY2VudGFnZSIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgTG9jYXRpb24gKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIEZlYXR1cmVzIC0gTG9jYXRpb246IEdyb3VwZWQgYnkgY291bnRlZCBMb2NhdGlvbiwgd2FybmluZz1UUlVFfQpnZ3Bsb3QoZGF0YSA9IGxvY2F0aW9uX2ZlYXR1cmVzKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IGNvdW50LCBmaWxsID0gZmVhdHVyZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmZWF0dXJlc19ncm91cGVkKSwgCiAgICBzdGF0PSdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBsb2NhdGlvbiwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBsb2NhdGlvbiwgeSA9IGNvdW50LCBsYWJlbCA9IGNvdW50LCBncm91cCA9IGZlYXR1cmVzX2dyb3VwZWQpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLjEsIHNpemUgPSAzCiAgKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGZWF0dXJlcyBwZXIgTG9jYXRpb24gKENvdW50KSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgojIyMgRnVuY3Rpb25hbGl0aWVzCgojIyMjIEZ1bmN0aW9uYWxpdGllcyB2cyBHZW5kZXIKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgZnVuY3Rpb25hbGl0aWVzIG9mIGEgc21hcnR3YXRjaCBhbmQgdGhlIHVzZXIncyBnZW5kZXIuCgpgYGB7ciBGdW5jdGlvbmFsaXRpZXMgLSBHZW5kZXI6IGRhdGFzZXQgY2FsY3VsYXRpb24sIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmdlbmRlcl9mdW5jdGlvbmFsaXRpZXMgPC0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWRfcm93cyAlPiUgCiAgZ3JvdXBfYnkoZ2VuZGVyLCBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUgCiAgZHJvcF9uYShmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkKYGBgCgpgYGB7ciBGdW5jdGlvbmFsaXRpZXMgLSBHZW5kZXI6IFBlcmNlbnRhZ2V9CiMgQ2hhcnQKZ2dwbG90KGdlbmRlcl9mdW5jdGlvbmFsaXRpZXMsIGFlcyh4ID0gZmFjdG9yKGdlbmRlciksIHkgPSBwZXJjICogMTAwLCBmaWxsID0gZmFjdG9yKGZ1bmN0aW9uYWxpdGllc19ncm91cGVkKSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uID0gImZpbGwiKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQiLCB0aXRsZSA9ICJQZXJjZW50YWdlIGRpc3RyaWJ1dGlvbiBvZiBGdW5jdGlvbmFsaXRpZXMgcGVyIEdlbmRlciIpICsKICB0aGVtZV9taW5pbWFsKGJhc2Vfc2l6ZSA9IDE0KSArCiAgZ2VvbV90ZXh0KGRhdGEgPSBnZW5kZXJfZnVuY3Rpb25hbGl0aWVzLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGwgPSBndWlkZV9sZWdlbmQodGl0bGUgPSAiRnVuY3Rpb25hbGl0aWVzIikpCmBgYAoKYGBge3IgRnVuY3Rpb25hbGl0aWVzIC0gR2VuZGVyOiBHcm91cGVkIGJ5IFBlcmMgR2VuZGVyLCB3YXJuaW5nPVRSVUV9CiMgQ2hhcnQKZ2dwbG90KGRhdGEgPSBnZW5kZXJfZnVuY3Rpb25hbGl0aWVzKSArIAogIGdlb21fYmFyKAogICAgYWVzKHggPSBnZW5kZXIsIHkgPSBwZXJjLCBmaWxsID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQsIGdyb3VwID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpLCAKICAgIHN0YXQgPSAnaWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gZ2VuZGVyLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IHBlcmMsIGxhYmVsID0gcmF0aW8sIGdyb3VwID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpLAogICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDEpLAogICAgdmp1c3QgPSAwLCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUGVyY2VudGFnZSIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGdW5jdGlvbmFsaXRpZXMgcGVyIEdlbmRlciAoJSkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKYGBge3IgRnVuY3Rpb25hbGl0aWVzIC0gR2VuZGVyOiBHcm91cGVkIGJ5IGNvdW50ZWQgR2VuZGVyLCB3YXJuaW5nPVRSVUV9CmdncGxvdChkYXRhID0gZ2VuZGVyX2Z1bmN0aW9uYWxpdGllcykgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gZ2VuZGVyLCB5ID0gY291bnQsIGZpbGwgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gZ2VuZGVyLCBzY2FsZXMgPSAiZnJlZV94IiwgZHJvcCA9IFRSVUUpICsKICBnZW9tX3RleHQoCiAgICBhZXMoeCA9IGdlbmRlciwgeSA9IGNvdW50LCBsYWJlbCA9IGNvdW50LCBncm91cCA9IGZ1bmN0aW9uYWxpdGllc19ncm91cGVkKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMC4xLCBzaXplID0gMwogICkgKwogIGxhYnMoeCA9ICJHZW5kZXIiLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEZ1bmN0aW9uYWxpdGllcyBwZXIgR2VuZGVyIChDb3VudCkiLCBzdWJ0aXRsZSA9ICJHcm91cGVkIGJhcnMgdmVyc2lvbiIpICsKICB0aGVtZV9idygpCmBgYAoKIyMjIyBGdW5jdGlvbmFsaXRpZXMgdnMgQWdlCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHRyYWNrZWQgZnVuY3Rpb25hbGl0aWVzIG9mIGEgc21hcnR3YXRjaCBwZXIgYWdlLgoKYGBge3IgRnVuY3Rpb25hbGl0aWVzIC0gQWdlOiBkYXRhc2V0IGNhbGN1bGF0aW9uLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQphZ2VfZnVuY3Rpb25hbGl0aWVzIDwtIGZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3MgJT4lIAogIGdyb3VwX2J5KGFnZSwgZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpICU+JSAKICBzdW1tYXJpc2UoY291bnQgPSBuKCkpICU+JSAKICBtdXRhdGUocGVyYyA9IGNvdW50L3N1bShjb3VudCksIHJhdGlvID0gc2NhbGVzOjpwZXJjZW50KHJvdW5kKHBlcmMsIDIpKSkgJT4lIAogIGRyb3BfbmEoZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpCmBgYAoKYGBge3IgRnVuY3Rpb25hbGl0aWVzIC0gQWdlOiBQZXJjZW50YWdlfQojIENoYXJ0CmdncGxvdChhZ2VfZnVuY3Rpb25hbGl0aWVzLCBhZXMoeCA9IGZhY3RvcihhZ2UpLCB5ID0gcGVyYyoxMDAsIGZpbGwgPSBmYWN0b3IoZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpKSkgKwogIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGggPSAwLjcsIHBvc2l0aW9uPSJmaWxsIikgKwogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlBlcmNlbnQiLCBmaWxsID0gImZ1bmN0aW9uYWxpdGllc19ncm91cGVkIiwgdGl0bGUgPSAiUGVyY2VudGFnZSBkaXN0cmlidXRpb24gb2YgRnVuY3Rpb25hbGl0aWVzIHBlciBBZ2UiKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gYWdlX2Z1bmN0aW9uYWxpdGllcywgYWVzKHkgPSBjb3VudCwgbGFiZWwgPSByYXRpbyksIHBvc2l0aW9uID0gcG9zaXRpb25fZmlsbCh2anVzdCA9IDAuNSkpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2xlZ2VuZCh0aXRsZT0iRnVuY3Rpb25hbGl0aWVzIikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSkKYGBgCgpgYGB7ciBGdW5jdGlvbmFsaXRpZXMgLSBBZ2U6IEdyb3VwZWQgYnkgUGVyYyBBZ2UsIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGFnZV9mdW5jdGlvbmFsaXRpZXMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGFnZSwgeSA9IHBlcmMsIGZpbGwgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksIAogICAgc3RhdCA9ICdpZGVudGl0eScsIHBvc2l0aW9uID0gJ2RvZGdlJwogICkgKwogIGZhY2V0X3dyYXAofiBhZ2UsIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gYWdlLCB5ID0gcGVyYywgbGFiZWwgPSByYXRpbywgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gc2NhbGVzOjpwZXJjZW50X2Zvcm1hdChhY2N1cmFjeSA9IDVMKSkgKwogIGxhYnMoeCA9ICJBZ2UiLCB5ID0gIlBlcmNlbnRhZ2UiLCB0aXRsZSA9ICJEaXN0cmlidXRpb24gb2YgRnVuY3Rpb25hbGl0aWVzIHBlciBBZ2UgKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIEZ1bmN0aW9uYWxpdGllcyAtIEFnZTogR3JvdXBlZCBieSBjb3VudGVkIEFnZSwgd2FybmluZz1UUlVFfQpnZ3Bsb3QoZGF0YSA9IGFnZV9mdW5jdGlvbmFsaXRpZXMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGFnZSwgeSA9IGNvdW50LCBmaWxsID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQsIGdyb3VwID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpLCAKICAgIHN0YXQ9J2lkZW50aXR5JywgcG9zaXRpb24gPSAnZG9kZ2UnCiAgKSArCiAgZmFjZXRfd3JhcCh+IGFnZSwgc2NhbGVzID0gImZyZWVfeCIsIGRyb3AgPSBUUlVFKSArCiAgZ2VvbV90ZXh0KAogICAgYWVzKHggPSBhZ2UsIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiQWdlIiwgeSA9ICJDb3VudCIsIHRpdGxlID0gIkRpc3RyaWJ1dGlvbiBvZiBGdW5jdGlvbmFsaXRpZXMgcGVyIEFnZSAoQ291bnQpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCiMjIyMgRnVuY3Rpb25hbGl0aWVzIHZzIExvY2F0aW9uCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIGZ1bmN0aW9uYWxpdGllcyBvZiBhIHNtYXJ0d2F0Y2ggcGVyIGFuZCB0aGUgdXNlcidzIGxvY2F0aW9uCgpgYGB7ciBGdW5jdGlvbmFsaXRpZXMgLSBMb2NhdGlvbjogZGF0YXNldCBjYWxjdWxhdGlvbiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbG9jYWNpb25fZnVuY3Rpb25hbGl0aWVzIDwtIGZ1bmN0aW9uYWxpdGllc19ncm91cGVkX3Jvd3MgJT4lIAogIGdyb3VwX2J5KGxvY2F0aW9uLCBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkgJT4lIAogIHN1bW1hcmlzZShjb3VudCA9IG4oKSkgJT4lIAogIG11dGF0ZShwZXJjID0gY291bnQvc3VtKGNvdW50KSwgcmF0aW8gPSBzY2FsZXM6OnBlcmNlbnQocm91bmQocGVyYywgMikpKSAlPiUgCiAgZHJvcF9uYShmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkKYGBgCgpgYGB7ciBGdW5jdGlvbmFsaXRpZXMgLSBMb2NhdGlvbjogUGVyY2VudGFnZX0KIyBDaGFydApnZ3Bsb3QobG9jYWNpb25fZnVuY3Rpb25hbGl0aWVzLCBhZXMoeCA9IGZhY3Rvcihsb2NhdGlvbiksIHkgPSBwZXJjKjEwMCwgZmlsbCA9IGZhY3RvcihmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCkpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb249ImZpbGwiKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50IiwgZmlsbCA9ICJmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mIEZ1bmN0aW9uYWxpdGllcyBwZXIgTG9jYXRpb24iKSArCiAgdGhlbWVfbWluaW1hbChiYXNlX3NpemUgPSAxNCkgKwogIGdlb21fdGV4dChkYXRhID0gbG9jYWNpb25fZnVuY3Rpb25hbGl0aWVzLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJGdW5jdGlvbmFsaXRpZXMiKSkgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUpKQpgYGAKCmBgYHtyIEZ1bmN0aW9uYWxpdGllcyAtIExvY2F0aW9uOiBHcm91cGVkIGJ5IFBlcmMgTG9jYXRpb24sIHdhcm5pbmc9VFJVRX0KIyBDaGFydApnZ3Bsb3QoZGF0YSA9IGxvY2FjaW9uX2Z1bmN0aW9uYWxpdGllcykgKyAKICBnZW9tX2JhcigKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBwZXJjLCBmaWxsID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQsIGdyb3VwID0gZnVuY3Rpb25hbGl0aWVzX2dyb3VwZWQpLCAKICAgIHN0YXQgPSAnaWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gbG9jYXRpb24sIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBwZXJjLCBsYWJlbCA9IHJhdGlvLCBncm91cCA9IGZ1bmN0aW9uYWxpdGllc19ncm91cGVkKSwKICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAxKSwKICAgIHZqdXN0ID0gMC4xLCBzaXplID0gMwogICkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgbGFicyh4ID0gIkxvY2F0aW9uIiwgeSA9ICJQZXJjZW50YWdlIiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEZ1bmN0aW9uYWxpdGllcyBwZXIgTG9jYXRpb24gKCUpIiwgc3VidGl0bGUgPSAiR3JvdXBlZCBiYXJzIHZlcnNpb24iKSArCiAgdGhlbWVfYncoKQpgYGAKCmBgYHtyIEZ1bmN0aW9uYWxpdGllcyAtIExvY2F0aW9uOiBHcm91cGVkIGJ5IGNvdW50ZWQgTG9jYXRpb24sIHdhcm5pbmc9VFJVRX0KZ2dwbG90KGRhdGEgPSBsb2NhY2lvbl9mdW5jdGlvbmFsaXRpZXMpICsgCiAgZ2VvbV9iYXIoCiAgICBhZXMoeCA9IGxvY2F0aW9uLCB5ID0gY291bnQsIGZpbGwgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCwgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksIAogICAgc3RhdD0naWRlbnRpdHknLCBwb3NpdGlvbiA9ICdkb2RnZScKICApICsKICBmYWNldF93cmFwKH4gbG9jYXRpb24sIHNjYWxlcyA9ICJmcmVlX3giLCBkcm9wID0gVFJVRSkgKwogIGdlb21fdGV4dCgKICAgIGFlcyh4ID0gbG9jYXRpb24sIHkgPSBjb3VudCwgbGFiZWwgPSBjb3VudCwgZ3JvdXAgPSBmdW5jdGlvbmFsaXRpZXNfZ3JvdXBlZCksCiAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSksCiAgICB2anVzdCA9IDAuMSwgc2l6ZSA9IDMKICApICsKICBsYWJzKHggPSAiTG9jYXRpb24iLCB5ID0gIkNvdW50IiwgdGl0bGUgPSAiRGlzdHJpYnV0aW9uIG9mIEZ1bmN0aW9uYWxpdGllcyBwZXIgTG9jYXRpb24gKENvdW50KSIsIHN1YnRpdGxlID0gIkdyb3VwZWQgYmFycyB2ZXJzaW9uIikgKwogIHRoZW1lX2J3KCkKYGBgCgoKCgoKCgoKCgoKIyMjIEFjdGl2aXRpZXMKCiMjIyMgQWN0aXZpdGllcyB2cyBHZW5kZXIKCldlIHdhbnQgdG8gaWRlbnRpZnkgaWYgdGhlcmUgYXJlIGEgcmVsYXRpb24gYmV0d2VlbiB0aGUgc3BvcnQgYWN0aXZpdGllcyB0cmFja2VkIGJ5IHVzZXJzIHBlciBnZW5kZXIuCgpgYGB7ciBHZW5kZXIgLSBBY3Rpdml0aWVzIHJlbGF0aW9ufQpnZW5kZXJfYWN0aXZpdGllcyA8LSBhY3Rpdml0aWVzX2dyb3VwZWRfcm93cyAlPiUgCiAgZ3JvdXBfYnkoZ2VuZGVyLCBhY3Rpdml0aWVzKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChjb3VudC9zdW0oY291bnQpKSkgJT4lIAogIGRyb3BfbmEoYWN0aXZpdGllcykKCiMgQ2hhcnQKZ2dwbG90KGdlbmRlcl9hY3Rpdml0aWVzLCBhZXMoeCA9IGZhY3RvcihnZW5kZXIpLCB5ID0gcGVyYyoxMDAsIGZpbGwgPSBmYWN0b3IoYWN0aXZpdGllcykpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb249ImZpbGwiKSArCiAgbGFicyh4ID0gIkdlbmRlciIsIHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiYWN0aXZpdGllcyIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mICdBY3Rpdml0aWVzJyBwZXIgR2VuZGVyIikgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBnZW9tX3RleHQoZGF0YSA9IGdlbmRlcl9hY3Rpdml0aWVzLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJBY3Rpdml0aWVzIikpCmBgYAojIyMjIEFjdGl2aXRpZXMgdnMgQWdlCgpXZSB3YW50IHRvIGlkZW50aWZ5IGlmIHRoZXJlIGFyZSBhIHJlbGF0aW9uIGJldHdlZW4gdGhlIHNwb3J0IGFjdGl2aXRpZXMgdHJhY2tlZCBieSB1c2VycyBwZXIgYWdlCgpgYGB7ciBBZ2UgLSBBY3Rpdml0aWVzIHJlbGF0aW9ufQphZ2VfYWN0aXZpdGllcyA8LSBhY3Rpdml0aWVzX2dyb3VwZWRfcm93cyAlPiUgCiAgZ3JvdXBfYnkoYWdlLCBhY3Rpdml0aWVzKSAlPiUgCiAgc3VtbWFyaXNlKGNvdW50ID0gbigpKSAlPiUgCiAgbXV0YXRlKHBlcmMgPSBjb3VudC9zdW0oY291bnQpLCByYXRpbyA9IHNjYWxlczo6cGVyY2VudChjb3VudC9zdW0oY291bnQpKSkgJT4lIAogIGRyb3BfbmEoYWN0aXZpdGllcykKCiMgQ2hhcnQKZ2dwbG90KGFnZV9hY3Rpdml0aWVzLCBhZXMoeCA9IGZhY3RvcihhZ2UpLCB5ID0gcGVyYyoxMDAsIGZpbGwgPSBmYWN0b3IoYWN0aXZpdGllcykpKSArCiAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aCA9IDAuNywgcG9zaXRpb249ImZpbGwiKSArCiAgbGFicyh4ID0gIkFnZSIsIHkgPSAiUGVyY2VudCIsIGZpbGwgPSAiYWN0aXZpdGllcyIsIHRpdGxlID0gIlBlcmNlbnRhZ2UgZGlzdHJpYnV0aW9uIG9mICdBY3Rpdml0aWVzJyBwZXIgQWdlIikgKwogIHRoZW1lX21pbmltYWwoYmFzZV9zaXplID0gMTQpICsKICBnZW9tX3RleHQoZGF0YSA9IGFnZV9hY3Rpdml0aWVzLCBhZXMoeSA9IGNvdW50LCBsYWJlbCA9IHJhdGlvKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9maWxsKHZqdXN0ID0gMC41KSkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBzY2FsZXM6OnBlcmNlbnRfZm9ybWF0KGFjY3VyYWN5ID0gNUwpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlPSJBY3Rpdml0aWVzIikpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1KSkKYGBg